source(file.path("..", "failing-builds-classify.R")) test_that("normalise_error collapses temp paths, versions, and package tokens", { a <- normalise_error( "In file /tmp/RtmpAb12/foo.c: RcppParallel 5.1.9 failed at 0xdeadbeef", package = "RcppParallel" ) expect_false(grepl("RtmpAb12", a)) expect_false(grepl("5\\.1\\.9", a)) expect_false(grepl("0xdeadbeef", a)) expect_true(grepl("", a)) expect_true(grepl("", a)) # Same root error across two versions collapses to one fingerprint. e1 <- "StanHeaders 2.32.1: tbb/tbb_stddef.h: No such file or directory" e2 <- "StanHeaders 2.33.0: tbb/tbb_stddef.h: No such file or directory" expect_identical( fingerprint_error(e1, "StanHeaders"), fingerprint_error(e2, "StanHeaders") ) }) test_that("normalise_error is safe on NA/empty input", { expect_identical(normalise_error(NA_character_), "") expect_identical(normalise_error(""), "") expect_identical(fingerprint_error(NA_character_), "") }) test_that("fingerprint_error picks the salient error line, not the last line", { txt <- paste( "* installing *source* package 'foo' ...", "error: bar.h: No such file or directory", "* removing '/tmp/lib/foo'", sep = "\n" ) fp <- fingerprint_error(txt, "foo") expect_true(grepl("no such file", fp)) expect_false(grepl("removing", fp)) }) test_that("classify_error matches the removed TBB header signature (makevars, auto)", { sig <- classify_error( "fatal error: tbb/tbb_stddef.h: No such file or directory" ) expect_identical(sig$id, "tbb-stddef-removed") expect_identical(sig$tier, "makevars") expect_true(sig$auto) expect_true(sig$matched) }) test_that("classify_error matches RcppParallel bundled-TBB failures", { sig <- classify_error( "Error: USE_TBB=Linux is not supported on this toolchain" ) expect_identical(sig$id, "rcppparallel-bundled-tbb") expect_identical(sig$tier, "patch") expect_true(sig$auto) }) test_that("system libuv link leak is classified but stays human-only (novel diff)", { sig <- classify_error("cannot open shared object file: libuv.so.1") expect_identical(sig$id, "system-libuv-link-leak") expect_true(sig$matched) expect_false(sig$auto) }) test_that("unknown signatures are never guessed at", { sig <- classify_error("segfault: memory not mapped at address") expect_identical(sig$id, "unclassified") expect_false(sig$matched) expect_false(sig$auto) expect_true(is.na(sig$tier)) }) test_that("propose_registry_entry fills a schema-valid entry for a known lever", { sig <- classify_error("tbb/tbb_stddef.h: No such file") json <- propose_registry_entry(sig, "StanHeaders", c("alpine", "ubuntu-2604")) entry <- jsonlite::fromJSON(json, simplifyVector = FALSE) expect_identical(entry$package, "StanHeaders") expect_identical(entry$versions, "*") expect_identical(entry$platforms, list("alpine", "ubuntu-2604")) expect_identical(entry$makevars$CPPFLAGS, "-DTBB_INTERFACE_NEW") expect_true(nzchar(entry$reason)) # No template -> no proposal (unclassified path). expect_null(propose_registry_entry(classify_error("weird"), "x", "alpine")) }) test_that("RcppParallel dependents are blocked, not proposed a per-package patch", { # Hundreds of packages fail on ubuntu-2604 only because their RcppParallel # dependency fails to build, so they carry RcppParallel's TBB error text. failures <- data.frame( name = c("ACEsimFit", "AovBay", "AdaptGauss"), platform = "ubuntu-2604", arch = "amd64", error_text = "Error: USE_TBB=Linux is not supported on this toolchain", stringsAsFactors = FALSE ) report <- build_triage_report(failures, registered_pkgs = character(0L)) grp <- Filter(function(g) g$signature == "rcppparallel-bundled-tbb", report)[[ 1L ]] # No bogus per-dependent entries (the patch targets RcppParallel's source). expect_null(grp$proposed_entries) expect_identical(grp$blocked_on, "RcppParallel") }) test_that("RcppParallel itself is still proposed when it is the failing package", { failures <- data.frame( name = "RcppParallel", platform = "ubuntu-2604", arch = "amd64", error_text = "Error: USE_TBB=Linux is not supported on this toolchain", stringsAsFactors = FALSE ) report <- build_triage_report(failures, registered_pkgs = character(0L)) grp <- report[[1L]] expect_identical(grp$signature, "rcppparallel-bundled-tbb") expect_false(is.null(grp$proposed_entries)) expect_true("RcppParallel" %in% names(grp$proposed_entries)) expect_null(grp$blocked_on) # RcppParallel is the target, not a dependent })