This is an automated email from the ASF dual-hosted git repository. leginee pushed a commit to branch bazel-migration in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit 1bdcd7a4dee1c0603f0a084f00e5b14e13024878 Author: Peter Kovacs <[email protected]> AuthorDate: Fri Aug 7 01:05:24 2026 +0200 test(unoapi): the whole qa/unoapi category — all 18 suites from one macro They are not 18 tests but 18 sets of DATA for one runner, so they are one macro. unoapi_test (build/rules/junit_test.bzl) takes only the four things that actually differ between the JunitTest_<module>_unoapi.mk files it ports — module, sce, xcl, tdoc — and `module` is the source directory name AND the adapter package (org.openoffice.<module>.qa.unoapi.Test) for all 18 without exception. svtools and qadevOOo move onto it too. The recorded gate was wrong on its key fact. -tdoc is NOT qadevOOo/testdocs: every makefile that sets it points at <module>/qa/unoapi/testdocuments, ten small per-module directories (~570 KB). qadevOOo/testdocs is only util.utils.getFullTestDocName's fallback when the argument is absent AND SRC_ROOT is set — a dmake-tree assumption no wired suite reaches. The gate that WAS real is data_dirs, the directory-preserving companion to data_tree (in gtest_test.bzl, shared by both launchers). data_tree maps one label to one path, which is right when a file's exact placement is under test, and wrong for a document ROOT: the runner joins names onto -tdoc at run time, so which documents a scenario opens is not a build-time fact — and dbaccess/forms have testdocuments/TestDB/, a nested directory data_tree cannot express at all. Each entry stages every file of a label under the chosen directory at its path relative to their LONGEST COMMON DIRECTORY: the strip prefix is derived, not declared, which is exact for the glob(["<dir>/**"]) filegroup the macro generates and keeps the call site to the one fact it knows. All 18 analyse clean; 16 have not been run yet. Reds recorded at the call site: dbaccess (its -ini props name a MySQL server no developer box has; only ORowSet and OSingleSelectQueryComposer reach for it) and sc (43 active objects vs 67 commented out upstream, each with its issue number, left verbatim). toolkit HAS been run, and is red on a real office defect — an ORPHANED MUTEX in acc.dll, diagnosed with cdb rather than guessed. The fixture is fine: the first object passes four whole interfaces, then the office hangs (Windows Application Hang event 1002, not a crash) and takes the other 52 with it. The main thread holds the SolarMutex in a WinProc focus dispatch and blocks in acc.dll's osl_acquireMutex; a binaryurp worker blocks on the same mutex; and !locks names that critical section (LockCount 2, exactly those two waiters) with an OwningThread that IS NOT IN THE LIVE THREAD LIST. So it is not a lock-order inversion and not the qadevOOo shutdown deadlock — a thread exited holding the lock, and an osl mutex is a plain CRITICAL_SECTION, so nothing recovers in-process. fixture_starts_office would not help; the hang is mid-run. Reachable by any assistive technology that attaches to a running office, not just this test. Fixing it is a source change in main/accessibility, so the suite stays wired and red, same disposition as //main/bridges:test_any_jni. Co-Authored-By: Claude Opus 5 <[email protected]> --- CLAUDE.md | 86 +++++++++++++++++++++++++++----- build/rules/gtest_test.bzl | 60 ++++++++++++++++++++-- build/rules/junit_test.bzl | 115 +++++++++++++++++++++++++++++++++++++++++- main/chart2/BUILD.bazel | 20 ++++++++ main/configmgr/BUILD.bazel | 17 +++++++ main/dbaccess/BUILD.bazel | 24 +++++++++ main/extensions/BUILD.bazel | 16 ++++++ main/forms/BUILD.bazel | 19 +++++++ main/framework/BUILD.bazel | 18 +++++++ main/linguistic/BUILD.bazel | 17 +++++++ main/qadevOOo/BUILD.bazel | 25 ++-------- main/sc/BUILD.bazel | 19 +++++++ main/sd/BUILD.bazel | 16 ++++++ main/sfx2/BUILD.bazel | 17 +++++++ main/starmath/BUILD.bazel | 16 ++++++ main/svtools/BUILD.bazel | 39 ++++----------- main/svx/BUILD.bazel | 19 ++++++- main/sw/BUILD.bazel | 20 ++++++++ main/test/readme.md | 119 ++++++++++++++++++++++++++++++++++++++++---- main/toolkit/BUILD.bazel | 58 +++++++++++++++++++++ main/ucb/BUILD.bazel | 17 +++++++ main/xmloff/BUILD.bazel | 16 ++++++ 22 files changed, 694 insertions(+), 79 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 3bb50a4efe..643e930908 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -352,16 +352,74 @@ test 🔨 C++ unit-test infra runnable — NOW THE FRONT-LINE TASK: br JVM. JAVA_HOME is pinned to the same JDK because OfficeConnection always passes -env:UNO_JAVA_JFW_ENV_JREHOME=true (the OFFICE's jvmfwk then reads it). - THE QUEUE IS LARGE AND WAS UNDER-COUNTED HERE: 18 qa/unoapi + 24 - qa/complex dirs, not the 4 modules this bucket used to name. Two - gates on the rest: (i) -tdoc — 11 of the 18 unoapi adapters pass a - test-document root ⇒ qadevOOo/testdocs must be staged, and data_tree - stages one FILE per entry, so a directory-preserving variant is the - next rule work (svtools went first precisely because its scenario - builds its document via SOfficeFactory and needs none); (ii) per-module - fixtures — svl/qa/complex/ConfigItems needs a C++ helper component, - and several qa/complex dirs (writerfilter's among them) have no - makefile.mk at all, i.e. were never wired upstream either. + qa/unoapi — WHOLE CATEGORY WIRED 2026-08-06, all 18, every one + //main/<module>:qa_unoapi. They are not 18 tests but 18 sets of DATA + for one runner, so they are ONE MACRO — unoapi_test (junit_test.bzl) + over the only four things that differ: module (= the source dir name, + which is ALSO the adapter package org.openoffice.<module>.qa.unoapi + .Test for all 18 without exception), sce, xcl, tdoc. Mirrors the + JunitTest_<module>_unoapi.mk files, which differ only in their + -Dorg.openoffice.test.arg.<name> lines. ANALYSED CLEAN (bazel build + --nobuild, all 18); NOT YET RUN — 16 of them have never executed here. + THE RECORDED -tdoc GATE WAS WRONG on the key fact: it is NOT + qadevOOo/testdocs. Every makefile that sets -tdoc points at + $(SRCDIR)/<module>/qa/unoapi/testdocuments — 10 small per-module dirs, + ~570 KB total (linguistic points at qa/unoapi ITSELF, i.e. passing + something non-null; neither of its 2 objects opens a document). + qadevOOo/testdocs is only the FALLBACK util.utils getFullTestDocName + takes when the arg is absent AND SRC_ROOT is set — a dmake-tree + assumption no wired suite reaches. So staging it is NOT a gate; + OOoRunnerLight/testdocs stay ⬜ for other reasons. + The gate that WAS real: data_dirs, the directory-preserving companion + to data_tree (gtest_test.bzl, shared by both launchers). data_tree + maps one label→one path, right when exact PLACEMENT is under test (a + mini installation has two files named bootstrap.ini); wrong for a + document ROOT, since the runner joins a name onto -tdoc AT RUN TIME so + which documents a scenario opens is not a build-time fact — and + dbaccess/forms testdocuments/TestDB/ is a NESTED dir data_tree cannot + express at all. Each entry stages every file of the label under the + chosen dir at its path relative to the LONGEST COMMON DIRECTORY of + that label's files: the strip prefix is DERIVED, not declared, which + is exact for the glob(["<dir>/**"]) filegroup the macro generates and + keeps the call site to the one fact it knows. + FIRST ONE RUN — //main/toolkit:qa_unoapi, RED on an ORPHANED MUTEX in + acc.dll (main/accessibility), left red. Fixture is FINE: it connects, + stages testdocuments/, and the first object + (toolkit.AccessibleDropDownComboBox = the Find toolbar combo) passes + FOUR whole interfaces; then the office HANGS and takes the other 52 + with it. cdb -pv (non-invasive, on the live hang): Windows logs + Application Hang event 1002, NOT a crash (Responding=False) — the Java + EOFException/DisposedException are only the consequence; the MAIN + thread holds the SolarMutex inside a WinProc dispatch + (Application::Execute→Yield→DispatchMessageW) delivering a focus event + ImplGrabFocus→ImplCallActivateListeners→VclEventListeners::Call→ + ootk!VCLXAccessibleComponent::WindowEventListener→acc.dll→ + sal3!osl_acquireMutex and BLOCKS; a binaryurp worker (the test's UNO + call) blocks on the SAME acc mutex; and !locks names the contended CS + (LockCount 2 = exactly those two waiters) whose OwningThread IS NOT IN + THE LIVE THREAD LIST. So NOT a lock-order inversion and NOT the + qadevOOo shutdown deadlock — the lock is ORPHANED: a thread exited + holding it, and an osl mutex is a plain CRITICAL_SECTION, so it can + never be acquired again and nothing recovers in-process. A real + product defect reachable by ANY assistive technology attaching to a + running office, not just this test; fix = source change in + main/accessibility, out of scope. Upstream's knownissues.xcl excludes + toolkit.AccessibleComboBox but NOT AccessibleDropDownComboBox, i.e. + upstream thinks the object is testable — consistent with a qa/ dir + gated behind ENABLE_UNIT_TESTS=NO for a decade that never ran. + TWO MORE REDS EXPECTED, both recorded at the call site: dbaccess (the only + -ini adapter; dbaccess.props names a MySQL server no dev box has, so + ORowSet + OSingleSelectQueryComposer fail and the other 7 objects do + not — wired anyway, a partial red naming which objects need a DB beats + an unwired suite) and sc (43 active objects vs 67 COMMENTED OUT, each + with its issue number — the honest upstream state, left verbatim). + Long poles size="large": sw (75 objects), toolkit (53), sc (43), + forms (34). + STILL ⬜: the 24 qa/complex dirs — unlike unoapi these are hand-written + suites with no shared shape, so one at a time. Gates: per-module + fixtures (svl/qa/complex/ConfigItems needs a C++ helper component) and + several (writerfilter's among them) have no makefile.mk at all, i.e. + were never wired upstream either. See main/test/readme.md. OPEN RED, LEFT RED ON PURPOSE — //main/bridges:test_any_jni. NOT a fixture problem and NOT caused by anything above: it fails in @@ -514,8 +572,12 @@ qadevOOo 🔨 OOoRunner.jar built (//main/qadevOOo:OOoRunner — qadevOOo JunitTest_qadevOOo_unoapi GREEN 2026-08-06 (//main/qadevOOo: qa_unoapi, ~16s) via uno_junit_test fixture_starts_office — see the OFFICE SHUTDOWN DEADLOCK note in the test bucket. - STILL ⬜: OOoRunnerLight, testdocs (needed by 11 of the 18 - unoapi adapters, which pass -tdoc). + STILL ⬜: OOoRunnerLight, testdocs. CORRECTION — testdocs is + NOT what the 11 -tdoc adapters need: they each point at their + OWN <module>/qa/unoapi/testdocuments (now staged per module via + data_dirs). qadevOOo/testdocs is only utils.getFullTestDocName's + fallback when -tdoc is absent AND SRC_ROOT is set, which no + wired suite hits. It is a leftover, not a blocker. testgraphical ⬜ (graphical/visual regression tests; needs instsetoo_native + qadevOOo) ── Remaining: Java-based ──────────────────────────────────────────────── diff --git a/build/rules/gtest_test.bzl b/build/rules/gtest_test.bzl index 34a15f1b89..861093d411 100644 --- a/build/rules/gtest_test.bzl +++ b/build/rules/gtest_test.bzl @@ -183,14 +183,66 @@ def _server_lines(server_exe, server_args, port): ":_portup", ] +def _stage_data_dirs(ctx, d, data_dirs): + """Stage whole fixture DIRECTORIES, preserving their internal shape. + + data_tree maps one label to one staged path, which is right when the exact + location of each file is the thing under test (a mini UNO installation has + two files named bootstrap.ini and only their directories tell them apart). + It is the wrong shape for a fixture that is simply "this directory of test + documents": the qadevOOo unoapi runner takes a document ROOT (-tdoc) and + joins a name onto it at runtime, so the build cannot know which documents a + scenario will open — the whole directory has to be there. + + Each entry is {label: "staged/dir"}, and every file the label provides is + staged under it at its path relative to the LONGEST COMMON DIRECTORY of that + label's files. Deriving the strip prefix instead of taking one as an + argument keeps the call site to the one fact it actually knows (where the + tree goes), and is exact for the usual `glob(["<dir>/**"])` filegroup: the + common directory IS <dir>, including when it holds only one file. A glob + that reaches outside its directory shortens the common prefix and so stages + deeper than intended, which is visible in the staged layout rather than + silent. + + Source files only, in practice: a mix of source and generated inputs shares + no directory prefix at all (bazel-out/... vs the execroot), which the same + rule would faithfully — and uselessly — reflect. + """ + staged = [] + for label, rel in data_dirs.items(): + files = label[DefaultInfo].files.to_list() + if not files: + fail("data_dirs entry %s -> %s: the label provides no files." % + (label.label, rel)) + + common = files[0].dirname.split("/") + for f in files[1:]: + parts = f.dirname.split("/") + n = 0 + for i in range(min(len(common), len(parts))): + if common[i] != parts[i]: + break + n = i + 1 + common = common[:n] + prefix = "/".join(common) + + for f in files: + sub = f.path[len(prefix) + 1:] if prefix else f.path + o = ctx.actions.declare_file(d + "/" + rel + "/" + sub) + ctx.actions.symlink(output = o, target_file = f) + staged.append(o) + return staged + # ── shared with junit_test.bzl ─────────────────────────────────────────────── -# The Java/UNO tests emit a launcher .bat of their own and need exactly these two +# The Java/UNO tests emit a launcher .bat of their own and need exactly these # primitives: a %~dp0-relative path to the staged install (bazel test's working -# directory is neither the execroot nor the exe's directory), and the escaping -# rules for a value baked into a .bat (the percent landmine above). Re-exported -# rather than copied, so both launchers keep one definition of each. +# directory is neither the execroot nor the exe's directory), the escaping rules +# for a value baked into a .bat (the percent landmine above), and directory +# staging. Re-exported rather than copied, so both launchers keep one +# definition of each. launcher_relpath = _windows_relpath launcher_expand_tokens = _expand_tokens +stage_data_dirs = _stage_data_dirs def _staged_gtest_test_impl(ctx): # The staging dir is normally "<name>.run". bin_layout makes it diff --git a/build/rules/junit_test.bzl b/build/rules/junit_test.bzl index eaf297802f..1635644f1f 100644 --- a/build/rules/junit_test.bzl +++ b/build/rules/junit_test.bzl @@ -43,7 +43,7 @@ load("@rules_java//java:defs.bzl", "java_library") load("@rules_java//java/common:java_info.bzl", "JavaInfo") load("//build:jre.bzl", "jre_home_native", "jre_java_exe") -load(":gtest_test.bzl", "launcher_expand_tokens", "launcher_relpath") +load(":gtest_test.bzl", "launcher_expand_tokens", "launcher_relpath", "stage_data_dirs") _JUNIT = "//build/third_party/junit:junit" _RUNNER = "org.junit.runner.JUnitCore" @@ -99,6 +99,11 @@ def _uno_junit_test_impl(ctx): ctx.actions.symlink(output = o, target_file = files[0]) staged.append(o) + # Whole fixture DIRECTORIES. The unoapi runner takes a document root and + # joins names onto it at run time, so which documents a scenario opens is not + # a build-time fact — the directory goes over as a directory. + staged += stage_data_dirs(ctx, d, ctx.attr.data_dirs) + # ── the staged office ─────────────────────────────────────────────────── uno_program_dir = None for f in ctx.files.uno_install: @@ -280,6 +285,7 @@ _uno_junit_test = rule( "jvm_flags": attr.string_list(), "uno_install": attr.label(allow_files = True, mandatory = True), "data_tree": attr.label_keyed_string_dict(allow_files = True), + "data_dirs": attr.label_keyed_string_dict(allow_files = True), "java_exe": attr.string(mandatory = True), "java_home": attr.string(mandatory = True), "fixture_starts_office": attr.bool(default = False), @@ -293,6 +299,7 @@ def uno_junit_test( deps = [], uno_install = "//main/staging:install", data_tree = {}, + data_dirs = {}, test_args = {}, jvm_flags = [], fixture_starts_office = False, @@ -319,6 +326,13 @@ def uno_junit_test( its working directory set to the staged dir, so a suite that does new File("test_documents", …) finds them. + data_dirs: {label: "relative/staged/dir"} fixture DIRECTORIES — every file + the label provides, staged under that directory keeping its shape (the + strip prefix is their longest common directory, so a + glob(["testdocuments/**"]) filegroup lands as testdocuments/…). Use this for + a document root the test names as a whole, such as the unoapi runner's + -tdoc; use data_tree when the exact placement of one file is the point. + fixture_starts_office: the LAUNCHER starts and kills the office, and the test attaches to it (`connect:`) instead of launching it (`path:`). Use this only for a suite that leaves the office unable to shut down, which otherwise @@ -348,8 +362,107 @@ def uno_junit_test( fixture_starts_office = fixture_starts_office, uno_install = uno_install, data_tree = data_tree, + data_dirs = data_dirs, java_exe = jre_java_exe(), java_home = jre_home_native(), size = size, **kwargs ) + +# The six runtime jars every qa/unoapi adapter needs. Upstream's makefiles vary +# — some list unoil.jar and jurt.jar, some do not — but the variation is +# accidental: the ones that omit them still run because gbuild puts the whole +# solver bin on the classpath. The Runner needs all six regardless (unoil is +# where every com.sun.star.* office API type lives). +_UNOAPI_DEPS = [ + "//main/qadevOOo:OOoRunner", + "//main/test:test_jar", + "//main/ridljar:ridl", + "//main/unoil:unoil", + "//main/jurt:jurt", + "//main/javaunohelper:juh_jar", +] + +def unoapi_test( + name, + module, + sce, + xcl = None, + ini = None, + tdoc = None, + srcs = None, + deps = [], + test_args = {}, + data_tree = {}, + data_dirs = {}, + **kwargs): + """One module's qa/unoapi suite — the qadevOOo UNOAPI runner over a live office. + + These 18 suites are not hand-written tests. Each is the SAME three-line + adapter (connect, hand org.openoffice.Runner a scenario file and the + connection description, assert its boolean result); what differs between + modules is only the data — which objects the scenario names, which + individual interface tests are excluded, and where the fixture documents + live. So the whole category is one macro over that data, mirroring the + JunitTest_<module>_unoapi.mk files it ports, which differ only in their + `-Dorg.openoffice.test.arg.*` lines. + + module: the source directory name, which is also the adapter's package — + org.openoffice.<module>.qa.unoapi.Test — for all 18 without exception. + + sce: the scenario file (`-o <object>` per line, commented-out entries being + the objects a known issue broke). xcl: the matching exclusion list of + individual interface tests. ini: a properties file, used only by dbaccess. + + Each is staged under its own basename and the argument points at the staged + copy, never at the source path: the arguments are read at RUN time, and + bazel test's working directory is neither the source tree nor the execroot. + These are NATIVE paths with single backslashes, deliberately — + org.openoffice.test.Argument.get is a bare System.getProperty, so none of + these values is macro-expanded and the doubling rtl::Bootstrap values need + (see gtest_test's `env`) would arrive here as literal double backslashes. + Staging by basename is also what makes the two adapters that IGNORE these + arguments work — chart2 and forms hardcode "sch.sce" / "forms.sce", + "knownissues.xcl" and "testdocuments" as paths relative to the working + directory instead of calling Argument.get. + + tdoc: the module's test-document directory, staged whole (see data_dirs) as + "testdocuments". Leave it unset for a scenario whose objects build their + documents through SOfficeFactory and load nothing from disk; the argument + then points at the staged dir itself, which is what upstream's argument-less + modules effectively get. + """ + files = {sce: sce.split("/")[-1]} + args = {"org.openoffice.test.arg.sce": "$(RUNDIR)\\" + files[sce]} + if xcl: + files[xcl] = xcl.split("/")[-1] + args["org.openoffice.test.arg.xcl"] = "$(RUNDIR)\\" + files[xcl] + if ini: + files[ini] = ini.split("/")[-1] + args["org.openoffice.test.arg.ini"] = "$(RUNDIR)\\" + files[ini] + + dirs = dict(data_dirs) + if tdoc: + native.filegroup( + name = name + "_tdoc", + srcs = native.glob([tdoc + "/**"]), + testonly = True, + ) + dirs[":" + name + "_tdoc"] = "testdocuments" + args["org.openoffice.test.arg.tdoc"] = "$(RUNDIR)\\testdocuments" + else: + args["org.openoffice.test.arg.tdoc"] = "$(RUNDIR)" + + files.update(data_tree) + args.update(test_args) + + uno_junit_test( + name = name, + srcs = srcs if srcs else ["qa/unoapi/Test.java"], + classes = ["org.openoffice.%s.qa.unoapi.Test" % module], + data_tree = files, + data_dirs = dirs, + test_args = args, + deps = deps + _UNOAPI_DEPS, + **kwargs + ) diff --git a/main/chart2/BUILD.bazel b/main/chart2/BUILD.bazel index 5d6de66d1a..8dfcee5713 100644 --- a/main/chart2/BUILD.bazel +++ b/main/chart2/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rename_file", "rsc_res") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -449,3 +450,22 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 12 objects, none commented out — the chart model and its wrappers (Diagram, +# Axis, DataSeries, Title, Legend, …). chart2's adapter is one of the TWO that +# ignore Argument.get and hardcode "sch.sce" / "knownissues.xcl" / +# "testdocuments" as paths relative to the working directory; staging by +# basename is what makes both spellings resolve to the same files. +unoapi_test( + name = "qa_unoapi", + module = "chart2", + sce = "qa/unoapi/sch.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", + size = "large", +) diff --git a/main/configmgr/BUILD.bazel b/main/configmgr/BUILD.bazel index 0fe5d132b8..1763ab9201 100644 --- a/main/configmgr/BUILD.bazel +++ b/main/configmgr/BUILD.bazel @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary") load("@bazel_skylib//rules:write_file.bzl", "write_file") load("//build/rules:gtest_test.bzl", "gtest_test") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -276,3 +277,19 @@ gtest_test( uno_install = "//main/staging:install", ) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# Two objects, configmgr.ConfigurationProvider and configmgr.DefaultProvider. +# Nothing to do with configmgr/qa/unit, which is red on a retired bootstrap +# mechanism (component_writeInfo): this one runs against a live office and only +# asks the running configuration manager for its UNO interfaces. No xcl and no +# testdocuments — upstream's makefile defines the sce and nothing else. +unoapi_test( + name = "qa_unoapi", + module = "configmgr", + sce = "qa/unoapi/module.sce", +) diff --git a/main/dbaccess/BUILD.bazel b/main/dbaccess/BUILD.bazel index f8c7d1efd8..cca3f646e7 100644 --- a/main/dbaccess/BUILD.bazel +++ b/main/dbaccess/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rename_file", "rsc_res") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -964,3 +965,26 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# The only adapter that takes -ini, and the reason is an EXTERNAL dependency: +# dbaccess.props names a MySQL server (jdbc.url=mysql://unoapi:3306/testDB) that +# no developer machine has. The objects that reach for it — ORowSet, +# OSingleSelectQueryComposer — will fail here; the rest (ODatabaseContext, +# OInteractionHandler, the dialogs) do not touch it. Wired anyway: a partial +# red that names which objects need a database is a better record than an +# unwired suite, and the file is staged so pointing it at a real server is a +# one-line change. +unoapi_test( + name = "qa_unoapi", + module = "dbaccess", + sce = "qa/unoapi/dbaccess.sce", + xcl = "qa/unoapi/knownissues.xcl", + ini = "qa/unoapi/dbaccess.props", + tdoc = "qa/unoapi/testdocuments", + size = "large", +) diff --git a/main/extensions/BUILD.bazel b/main/extensions/BUILD.bazel index 99d2d7571c..13f6e34aa6 100644 --- a/main/extensions/BUILD.bazel +++ b/main/extensions/BUILD.bazel @@ -9,6 +9,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") +load("//build/rules:junit_test.bzl", "unoapi_test") # ── Component XML files (for services.rdb via postprocess) ──────────────────── exports_files(glob([ @@ -765,3 +766,18 @@ cc_binary( # Deferred: mozbootstrap.uno — Linux/macOS only (skipped on Windows). # Deferred: activex/msidl, activex/main — ActiveX/COM tooling required. # ───────────────────────────────────────────────────────────────────────────── + +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# One object, pcr.ObjectInspector — listed TWICE on purpose. The comment in +# extensions.sce explains it: the Runner only prints "N of M tests failed" when +# it ran more than one test, and the harness above it parses that line. +unoapi_test( + name = "qa_unoapi", + module = "extensions", + sce = "qa/unoapi/extensions.sce", +) diff --git a/main/forms/BUILD.bazel b/main/forms/BUILD.bazel index f16531f2af..1b93e43a82 100644 --- a/main/forms/BUILD.bazel +++ b/main/forms/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary") load("//build/rules:rsc_pipeline.bzl", "rsc_res") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -157,3 +158,21 @@ rsc_res( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 34 objects, the largest of the control/model suites. The second of the two +# adapters that hardcode their paths instead of calling Argument.get (see +# chart2). testdocuments holds TestDB, a directory — which is why the fixture +# has to go over as a directory tree and not as a list of files. +unoapi_test( + name = "qa_unoapi", + module = "forms", + sce = "qa/unoapi/forms.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", + size = "large", +) diff --git a/main/framework/BUILD.bazel b/main/framework/BUILD.bazel index 4dc6dbb126..ab703565e8 100644 --- a/main/framework/BUILD.bazel +++ b/main/framework/BUILD.bazel @@ -2,6 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -562,3 +563,20 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 27 objects across the framework services — Desktop, Frame, the dispatch +# providers, the URL transformer, type detection. Its testdocuments carries the +# two link documents and XTypeDetection.sxw that the detection objects open. +unoapi_test( + name = "qa_unoapi", + module = "framework", + sce = "qa/unoapi/framework.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", + size = "large", +) diff --git a/main/linguistic/BUILD.bazel b/main/linguistic/BUILD.bazel index 6a53ef672f..d5310af984 100644 --- a/main/linguistic/BUILD.bazel +++ b/main/linguistic/BUILD.bazel @@ -1,6 +1,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -96,3 +97,19 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# Two objects, lng.DicList and lng.LinguProps. Upstream points -tdoc at +# qa/unoapi ITSELF (there is no testdocuments subdirectory), which is a way of +# passing something non-null rather than a real document root — neither object +# opens a document. Staged dir it is, same as svtools. +unoapi_test( + name = "qa_unoapi", + module = "linguistic", + sce = "qa/unoapi/lng.sce", + xcl = "qa/unoapi/knownissues.xcl", +) diff --git a/main/qadevOOo/BUILD.bazel b/main/qadevOOo/BUILD.bazel index 6dc8f1ee4a..d43c634014 100644 --- a/main/qadevOOo/BUILD.bazel +++ b/main/qadevOOo/BUILD.bazel @@ -1,5 +1,5 @@ load("@rules_java//java:defs.bzl", "java_library") -load("//build/rules:junit_test.bzl", "uno_junit_test") +load("//build/rules:junit_test.bzl", "uno_junit_test", "unoapi_test") # ── OOoRunner.jar ──────────────────────────────────────────────────────────── # The qadevOOo test framework (lib.*, base.*, util.*, share.*, mod.* …) used as a @@ -91,27 +91,12 @@ java_library( # which are what this target is for, then run and report. What is given up is # tearDown's check that the office exits 0, which for this suite is exactly the # thing that is broken and would otherwise cost 300 s per run to re-observe. -uno_junit_test( +unoapi_test( name = "qa_unoapi", - srcs = ["qa/unoapi/Test.java"], - classes = ["org.openoffice.qadevOOo.qa.unoapi.Test"], + module = "qadevOOo", + sce = "qa/unoapi/qadevOOo.sce", + xcl = "qa/unoapi/knownissues.xcl", fixture_starts_office = True, - data_tree = { - "qa/unoapi/qadevOOo.sce": "qadevOOo.sce", - "qa/unoapi/knownissues.xcl": "knownissues.xcl", - }, - test_args = { - "org.openoffice.test.arg.sce": "$(RUNDIR)\\qadevOOo.sce", - "org.openoffice.test.arg.xcl": "$(RUNDIR)\\knownissues.xcl", - }, - deps = [ - ":OOoRunner", - "//main/test:test_jar", - "//main/ridljar:ridl", - "//main/unoil:unoil", - "//main/jurt:jurt", - "//main/javaunohelper:juh_jar", - ], ) uno_junit_test( diff --git a/main/sc/BUILD.bazel b/main/sc/BUILD.bazel index 2623ee76fb..6e72582595 100644 --- a/main/sc/BUILD.bazel +++ b/main/sc/BUILD.bazel @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") load("//build/rules:sdi_target.bzl", "sdi_target") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -1277,3 +1278,21 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 43 active objects — and 67 commented out, each with the issue number that +# broke it. That ratio is the honest state of the Calc unoapi suite upstream, +# not something lost in migration; the commented lines are left exactly as they +# are so re-enabling one is a one-character edit. +unoapi_test( + name = "qa_unoapi", + module = "sc", + sce = "qa/unoapi/sc.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", + size = "large", +) diff --git a/main/sd/BUILD.bazel b/main/sd/BUILD.bazel index 097e04782c..509ac17750 100644 --- a/main/sd/BUILD.bazel +++ b/main/sd/BUILD.bazel @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") load("//build/rules:sdi_target.bzl", "sdi_target") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -932,3 +933,18 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 12 objects — the draw pages, layers and presentation wrappers. No +# testdocuments: every object is built through SOfficeFactory from an empty +# document, so upstream's makefile passes no -tdoc either. +unoapi_test( + name = "qa_unoapi", + module = "sd", + sce = "qa/unoapi/sd.sce", + xcl = "qa/unoapi/knownissues.xcl", +) diff --git a/main/sfx2/BUILD.bazel b/main/sfx2/BUILD.bazel index ce4791aa23..eb38accf2f 100644 --- a/main/sfx2/BUILD.bazel +++ b/main/sfx2/BUILD.bazel @@ -4,6 +4,7 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") load("//build/rules:sdi_target.bzl", "sdi_package", "sdi_target") load("//build/rules:gtest_test.bzl", "gtest_test") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -265,3 +266,19 @@ gtest_test( # enumerate it in runtime_dlls. uno_install = "//main/staging:install", ) + +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# Three objects (the standalone document-info object and the frame loaders), +# with the .sdw/.stw documents they open staged beside them. +unoapi_test( + name = "qa_unoapi", + module = "sfx2", + sce = "qa/unoapi/sfx.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", +) diff --git a/main/starmath/BUILD.bazel b/main/starmath/BUILD.bazel index 02a71517c3..bcc5ba1e5d 100644 --- a/main/starmath/BUILD.bazel +++ b/main/starmath/BUILD.bazel @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") load("//build/rules:sdi_target.bzl", "sdi_target") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -272,3 +273,18 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 9 objects: the model, the two accessibles, and the XML import/export filters. +# Target named qa_unoapi like every other module; upstream's makefile calls it +# sm_unoapi after the library rather than the directory. +unoapi_test( + name = "qa_unoapi", + module = "starmath", + sce = "qa/unoapi/sm.sce", + xcl = "qa/unoapi/knownissues.xcl", +) diff --git a/main/svtools/BUILD.bazel b/main/svtools/BUILD.bazel index 377b44e1ca..13718ed292 100644 --- a/main/svtools/BUILD.bazel +++ b/main/svtools/BUILD.bazel @@ -2,7 +2,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") -load("//build/rules:junit_test.bzl", "uno_junit_test") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -235,36 +235,15 @@ rsc_res( # entries are commented out with the issue number that broke them (#i110988, # #i88276, …), so this suite is exactly one object today: # svtools.AccessibleTabBar. knownissues.xcl is the second half of that -# mechanism — a list of individual interface tests to skip. Both are staged -# rather than passed as source paths, because the arguments are read at run time -# and bazel test's working directory is neither the source tree nor the execroot. -uno_junit_test( +# mechanism — a list of individual interface tests to skip. +# +# No tdoc: AccessibleTabBar builds its document through SOfficeFactory and loads +# nothing from disk, and svtools ships no qa/unoapi/testdocuments to stage. +unoapi_test( name = "qa_unoapi", - srcs = ["qa/unoapi/Test.java"], - classes = ["org.openoffice.svtools.qa.unoapi.Test"], - data_tree = { - "qa/unoapi/svtools.sce": "svtools.sce", - "qa/unoapi/knownissues.xcl": "knownissues.xcl", - }, - test_args = { - "org.openoffice.test.arg.sce": "$(RUNDIR)\\svtools.sce", - "org.openoffice.test.arg.xcl": "$(RUNDIR)\\knownissues.xcl", - # The runner's test-document root. AccessibleTabBar builds its document - # through SOfficeFactory and loads nothing from disk, so no qadevOOo - # testdocs tree is staged here; a suite whose .sce names objects that DO - # open a fixture document will need one. Upstream leaves this argument - # unset entirely (the makefile defines no DEFS), which is why its own - # Test.java would pass null. - "org.openoffice.test.arg.tdoc": "$(RUNDIR)", - }, - deps = [ - "//main/qadevOOo:OOoRunner", - "//main/test:test_jar", - "//main/ridljar:ridl", - "//main/unoil:unoil", - "//main/jurt:jurt", - "//main/javaunohelper:juh_jar", - ], + module = "svtools", + sce = "qa/unoapi/svtools.sce", + xcl = "qa/unoapi/knownissues.xcl", ) exports_files(glob(["**/*.component"])) diff --git a/main/svx/BUILD.bazel b/main/svx/BUILD.bazel index 29cb72bc25..8e4eaac59f 100644 --- a/main/svx/BUILD.bazel +++ b/main/svx/BUILD.bazel @@ -3,6 +3,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rename_file", "rsc_res") load("//build/rules:sdi_target.bzl", "sdi_package", "sdi_target") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -995,4 +996,20 @@ filegroup( visibility = ["//main/postprocess:__pkg__"], ) -exports_files(glob(["**/*.component"])) \ No newline at end of file +exports_files(glob(["**/*.component"])) + +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 11 objects — the shape wrappers and the graphic-import path, which is why the +# two JPEGs are in testdocuments alongside the .sxd. +unoapi_test( + name = "qa_unoapi", + module = "svx", + sce = "qa/unoapi/svx.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", +) diff --git a/main/sw/BUILD.bazel b/main/sw/BUILD.bazel index bf76cb8804..d7a47133ff 100644 --- a/main/sw/BUILD.bazel +++ b/main/sw/BUILD.bazel @@ -4,6 +4,7 @@ load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") load("//build/rules:rsc_pipeline.bzl", "rsc_res") load("//build/rules:sdi_target.bzl", "sdi_target") load("//build/rules:gtest_test.bzl", "gtest_test") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -1544,3 +1545,22 @@ gtest_test( # than enumerating the closure (see gtest_test's uno_install). uno_install = "//main/staging:install", ) + +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 75 objects, the largest unoapi scenario in the tree: the whole Writer text +# model (paragraphs, portions, tables, fields, sections, bookmarks, the +# embedded-object and mail-merge paths). Expect this one to be the long pole of +# the category — every object is instantiated in the running office. +unoapi_test( + name = "qa_unoapi", + module = "sw", + sce = "qa/unoapi/sw.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", + size = "large", +) diff --git a/main/test/readme.md b/main/test/readme.md index 30f251e679..e69242d1ec 100644 --- a/main/test/readme.md +++ b/main/test/readme.md @@ -419,6 +419,9 @@ Each of these was invisible until a foreign process loaded our DLLs: | `//main/svtools:qa_unoapi` | the first UNOAPI suite ever run here — 26 interface/property checks on `svtools.AccessibleTabBar` | ~25 s | | `//main/qadevOOo:qa_unoapi` | the runner testing itself (`qadevOOo.SelfTest`) — the guard on the framework the other unoapi suites are built out of. Needs `fixture_starts_office`, see below | ~16 s | +The other 16 `qa/unoapi` suites are wired but have not been run yet — see +[the category section](#the-whole-qaunoapi-category-all-18-wired) below. + ### When the office will not shut down: `fixture_starts_office` `qadevOOo:qa_unoapi` is the suite that motivated this. With the faithful @@ -463,19 +466,113 @@ It is **opt-in and costs something**: `tearDown`'s check that the office terminates cleanly and exits 0. Use it only where that check is the thing that is broken, and record why. -### The rest of the category, and what each needs - -There are **18** `qa/unoapi` and **24** `qa/complex` directories in the tree, so -this is a queue, not a leftover. Two things gate the remainder: +### The whole `qa/unoapi` category: all 18 wired + +Every `qa/unoapi` directory in the tree is now a target, all named +`//main/<module>:qa_unoapi`. They are not 18 different tests — they are 18 sets +of *data* for one runner, which is why they are one macro, `unoapi_test` +(`build/rules/junit_test.bzl`), over the four things that actually differ: + +| | | +| --- | --- | +| `module` | the source directory name, which is also the adapter's package — `org.openoffice.<module>.qa.unoapi.Test` for all 18 without exception | +| `sce` | the scenario: one `-o <object>` per line, commented-out lines carrying the issue number that broke that object | +| `xcl` | the matching exclusion list of individual interface tests | +| `tdoc` | the module's `qa/unoapi/testdocuments` directory, when it has one | + +That mirrors the `JunitTest_<module>_unoapi.mk` files being ported, which differ +only in their `-Dorg.openoffice.test.arg.*` lines. + +**`-tdoc` is per-module, and an earlier note here had it wrong.** It is *not* +`qadevOOo/testdocs` — every makefile that sets it points at +`$(SRCDIR)/<module>/qa/unoapi/testdocuments`, 10 small directories totalling +about 570 KB (`linguistic` is the odd one, pointing at `qa/unoapi` itself, which +is a way of passing something non-null: neither of its two objects opens a +document). `qadevOOo/testdocs` is only the *fallback* `util.utils` +`getFullTestDocName` reaches for when the argument is absent and `SRC_ROOT` is +set — a dmake-tree assumption, and not a path any wired suite takes. + +The gate this did need was **`data_dirs`**, the directory-preserving companion +to `data_tree`, now in `gtest_test.bzl` and shared by both launchers. `data_tree` +maps one label to one staged path, which is right when the exact placement of a +file is the thing under test (a mini UNO installation has two files named +`bootstrap.ini` and only their directories tell them apart). It is the wrong +shape for a document *root*: the runner joins a document name onto `-tdoc` at +run time, so which documents a scenario opens is not a build-time fact and the +directory has to go over whole — including `dbaccess`'s and `forms`'s +`testdocuments/TestDB/`, a nested directory `data_tree` cannot express at all. +Each entry stages every file the label provides under the chosen directory, at +its path relative to the **longest common directory** of that label's files; the +strip prefix is derived rather than declared, which is exact for the +`glob(["<dir>/**"])` filegroup the macro generates and keeps the call site to the +one fact it knows — where the tree goes. + +Expect reds, and expect them to be informative rather than structural — this is +the first time these suites have run here at all. + +#### First one run: `toolkit`, red on an **orphaned mutex in `acc.dll`** + +The fixture works — it connects, stages `testdocuments/`, and the first object +(`toolkit.AccessibleDropDownComboBox`, the Find toolbar's combo box) passes four +whole interfaces. Then the office **hangs**, and takes the other 52 objects with +it. Diagnosed with a non-invasive `cdb -pv -p <pid>` against the live hang: + +- Windows logs an **Application Hang** (event 1002), *not* a crash; the office + stops pumping messages and `Process.Responding` is `False`. The Java side sees + only the consequence — `EOFException` on the URP pipe, then `DisposedException` + out of `tearDown`. +- The **main thread holds the SolarMutex** (inside a WinProc dispatch under + `Application::Execute` → `Yield` → `DispatchMessageW`) delivering a focus + event: `Window::ImplGrabFocus` → `ImplCallActivateListeners` → + `VclEventListeners::Call` → `ootk!VCLXAccessibleComponent::WindowEventListener` + → `acc.dll` → `sal3!osl_acquireMutex`, where it blocks. +- A **`binaryurp` worker** — the test's incoming UNO call — blocks on the *same* + `acc.dll` mutex. +- `!locks` names the contended critical section (`LockCount 2`, exactly those two + waiters) and its `OwningThread` — **and that thread ID is not in the live + thread list.** + +So it is *not* a lock-order inversion, and not the solar-mutex-vs-URP shutdown +deadlock recorded above for `qadevOOo`: the lock is **orphaned**. A thread left +`acc.dll`'s mutex held and exited, and an osl mutex is a plain Windows +`CRITICAL_SECTION` — once orphaned it can never be acquired again, so the first +VCL event *and* the first UNO call that reach accessibility both block forever. +Nothing recovers it in-process. + +That is a real product defect reachable by any assistive technology that attaches +to a running office, not just by this test, and fixing it is a source change in +`main/accessibility` — out of scope here. The suite stays wired and red, the same +disposition as `//main/bridges:test_any_jni`. Upstream's `knownissues.xcl` +excludes `toolkit.AccessibleComboBox` but **not** `AccessibleDropDownComboBox`, +i.e. upstream considers this object testable — consistent with a `qa/` directory +gated behind `ENABLE_UNIT_TESTS=NO` for a decade that has simply never run. + +Two more reds are known in advance: + +- **`dbaccess`** is the only adapter taking `-ini`, and its `dbaccess.props` + names a MySQL server (`jdbc.url=mysql://unoapi:3306/testDB`) no developer + machine has. `ORowSet` and `OSingleSelectQueryComposer` reach for it; the + other seven objects do not. Wired anyway — a partial red that names which + objects need a database beats an unwired suite, and the props file is staged, + so pointing it at a real server is a one-line change. +- **`sc`** has 43 active objects and **67 commented out**, each with its issue + number. That ratio is the honest upstream state of the Calc suite, not + something lost in migration; the lines are left exactly as they are. + +The long poles are `sw` (75 objects), `toolkit` (53), `sc` (43) and `forms` +(34) — every object is instantiated in a running office, so those four take +`size = "large"`. + +### What is left + +That leaves the **24** `qa/complex` directories, which unlike unoapi are +hand-written suites with no shared shape, so they come one at a time. Two things +gate them: -- **`-tdoc`** — 11 of the 18 unoapi adapters pass a test-document root, which - means staging `qadevOOo/testdocs` (53 entries, some of them directories). The - rule's `data_tree` stages one *file* per entry; a directory-preserving - variant is the next piece of rule work. `svtools`' scenario builds its - document through `SOfficeFactory` and needs none, which is why it went first. - **per-module fixtures** — `svl/qa/complex/ConfigItems` needs a C++ helper - component built alongside; `writerfilter/qa/complex` and several others have - no `makefile.mk` at all upstream, i.e. they were never wired there either. + component built alongside; +- **several were never wired upstream either** — `writerfilter/qa/complex` and + others have no `makefile.mk` at all. ## The sal suite is deliberately NOT a green gate diff --git a/main/toolkit/BUILD.bazel b/main/toolkit/BUILD.bazel index e5b06cb0a5..264c1943a6 100644 --- a/main/toolkit/BUILD.bazel +++ b/main/toolkit/BUILD.bazel @@ -1,6 +1,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -131,3 +132,60 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 53 objects: every UnoControl* pair (control + model) plus the AWT peers. The +# single fixture document is poliball.gif, loaded by the image-control tests. +# +# RED, AND LEFT RED — an ORPHANED MUTEX IN acc.dll HANGS THE OFFICE. The fixture +# itself is fine: the suite connects, and the FIRST object +# (toolkit.AccessibleDropDownComboBox, the Find toolbar's combo box) passes four +# whole interfaces — XAccessibleExtendedComponent, XAccessibleEventBroadcaster, +# XAccessibleAction and the rest — before anything goes wrong. It dies on the +# NEXT object creation, and takes all 53 with it. +# +# Diagnosed, not guessed (`cdb -pv -p <pid>`, non-invasive, against the live +# hang): +# +# * Windows logs an "Application Hang" (event 1002), NOT a crash — the office +# stops pumping messages and is killed; Process.Responding is False. What the +# Java side sees is only the consequence: an EOFException on the URP pipe, +# then DisposedException out of tearDown. +# * the office's MAIN thread holds the SolarMutex (it is inside a WinProc +# dispatch under Application::Execute -> Yield -> DispatchMessageW) delivering +# a focus event: Window::ImplGrabFocus -> ImplCallActivateListeners -> +# VclEventListeners::Call -> ootk!VCLXAccessibleComponent::WindowEventListener +# -> acc.dll -> sal3!osl_acquireMutex, where it BLOCKS. +# * a binaryurp worker — the test's incoming UNO call — blocks in the SAME +# acc.dll mutex, one frame below binaryurp. +# * `!locks` names the contended critical section (LockCount 2, i.e. exactly +# those two waiters) and its OwningThread, and that thread ID IS NOT IN THE +# LIVE THREAD LIST. +# +# So this is not a lock-ORDER inversion and not the solar-mutex-vs-URP shutdown +# deadlock already recorded for qadevOOo (see main/test/readme.md): the lock is +# ORPHANED. Some thread left acc.dll's mutex held and exited, after which an osl +# mutex — a plain Windows CRITICAL_SECTION — can never be acquired again, so the +# first VCL event and the first UNO call that reach accessibility both block +# forever. Nothing can recover it in-process. +# +# Fixing that is a SOURCE change in main/accessibility, which this branch does +# not make, so the suite stays wired and red: it is an accurate report of a real +# product defect, and the same defect is reachable by any assistive technology +# that attaches to a running office, not just by this test. Upstream's own +# knownissues.xcl excludes toolkit.AccessibleComboBox but NOT +# AccessibleDropDownComboBox, i.e. upstream considers this object testable — +# consistent with a qa/ dir that has been gated behind ENABLE_UNIT_TESTS=NO for a +# decade and has simply not run. +unoapi_test( + name = "qa_unoapi", + module = "toolkit", + sce = "qa/unoapi/toolkit.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", + size = "large", +) diff --git a/main/ucb/BUILD.bazel b/main/ucb/BUILD.bazel index 45c1cfcccc..7676ef4319 100644 --- a/main/ucb/BUILD.bazel +++ b/main/ucb/BUILD.bazel @@ -1,6 +1,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -458,3 +459,19 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 10 objects — the broker itself plus one content provider per scheme (file, +# hierarchy, package, help, FTP). ucpftp.FTPContentProvider is the one to watch: +# it is instantiated, not connected to anything, but it is the only object here +# that names a network protocol. +unoapi_test( + name = "qa_unoapi", + module = "ucb", + sce = "qa/unoapi/ucb.sce", + xcl = "qa/unoapi/knownissues.xcl", +) diff --git a/main/xmloff/BUILD.bazel b/main/xmloff/BUILD.bazel index c80cd1c419..2b464f7459 100644 --- a/main/xmloff/BUILD.bazel +++ b/main/xmloff/BUILD.bazel @@ -1,6 +1,7 @@ package(default_visibility = ["//visibility:public"]) load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("//build/rules:junit_test.bzl", "unoapi_test") _DEFINES = [ "WNT", "GUI", "WIN32", @@ -163,3 +164,18 @@ filegroup( exports_files(glob(["**/*.component"])) +# ── qa/unoapi ──────────────────────────────────────────────────────────────── +# The qadevOOo UNOAPI runner over a live office: Test.java hands +# org.openoffice.Runner the scenario below, and the Runner instantiates each +# named object in the running office and checks every interface and property it +# declares against the UNO type description. See build/rules/junit_test.bzl. +# +# 10 objects, the XML import/export filter services. emptyChart.sds is the one +# fixture document — the chart filters need a chart to round-trip. +unoapi_test( + name = "qa_unoapi", + module = "xmloff", + sce = "qa/unoapi/xmloff.sce", + xcl = "qa/unoapi/knownissues.xcl", + tdoc = "qa/unoapi/testdocuments", +)
