Tika-Server REST UAT Script
A portable shell script that exercises the tika-server REST surface against an already-running server. The same script is used as the docker image smoke test, the e2e integration test, and as part of the source-release verification.
Where it lives
release-tools/uat/
├── run-uat.sh # the script
└── test-files/
├── testPDF.pdf
├── testHTML.html
├── testOCR_spacing.png
└── test_recursive_embedded.docx
All four files must be present — the script exits 2 if any is missing. Point
TIKA_UAT_TEST_FILES at another directory to override the location.
What it covers
Roughly 30 REST endpoint checks across the default-mode endpoints, header behavior, and error handling — the same surface enumerated in the manual walkthrough at Tika-Server Integration Testing, translated to bash + curl assertions.
Coverage includes:
-
/version,/parsers,/detectors,/mime-types(introspection) -
/detect(mime detection) -
/tika/text,/tika/html,/tika/xml,/tika/json(parse) -
/meta,/meta/{field}(metadata) -
/rmeta,/rmeta/text(recursive metadata) -
/unpack/all(embedded extraction; verifies the response is a valid zip) -
/language -
/meta/form,/rmeta/form(multipart variants) -
allowPerRequestConfig=falsegating, both enforcement points: the path-based filter (/meta/config,/rmeta/config,/tika/config,/unpack/all/configall return 403) and the content-based gate (a multipartconfigpart on/unpackreturns 403). Note there is no/unpack/configpath — the config-variant is/unpack/all/config. -
/statusis not registered by default (returns 404 unless explicitly listed underendpoints) -
A removed
X-Tika-OCRskipOcrheader is ignored rather than rejected (asserts HTTP 200 only; theX-Tika-OCR*/X-Tika-PDF*families no longer exist) -
Handler selection:
/tika/textis body-only (no<title>in the output),/tika/jsonwith no handler named matches/tika/json/md(markdown is the default), and an unrecognized handler name returns 400 rather than silently falling back -
/metawithAccept: application/rdf+xmlreturns XMP — content negotiation, not a distinct path. Worth a smoke check because this shipped broken in 4.0.0-alpha-1 and beta-1: the resource failed to load and the endpoint 406’d -
Removed endpoints stay removed (
/translate/*returns 404) -
404 / 405 error handling
-
Exception reporting on a corrupt document (TIKA-4848):
/rmetaembedstk:exception:container-exceptionat200; raw/tikareturns422with a content-only body;/unpackand/meta/{field}carry the container exception in their422bodies, asserted free of this server’s own frames (PipesParsingHelper,MetadataResource) -
OCR (
PUT /tika/textof an image whose text only exists as pixels): skipped when the server has no tesseract (the minimal image / a plainjava -jarserver), and a hard failure whenTIKA_UAT_REQUIRE_OCR=1is set.docker-tool.sh test-uatsets that env var for the-fullimage, so OCR is asserted there and skipped for the minimal image.
The inference pass
A second run, against a server started on release-tools/uat/uat-inference-config.json,
exercises what the default-mode run cannot: the engine wiring between tika-server, its forked
parse worker and an inference engine. Nothing real is called. MockInferenceServer.java in
the same directory stands in for a hosted OCR model and an embedding model; it speaks the two
OpenAI-shaped endpoints Tika’s engines use plus the health check, has no dependencies beyond
the JDK, and runs from source (java release-tools/uat/MockInferenceServer.java 18080 --flaky).
With --flaky it refuses every other request with a 429 first, the way a concurrency-capped
engine answers, so the pass proves the client’s retry as well.
With TIKA_UAT_INFERENCE=1 the script adds:
-
T40/T41: the mock OCR model is the configured text recognizer; its markdown comes back as text, and the HTML table it emits (document-OCR models write tables that way) is parsed into a
<table>, not escaped. -
T42/T43: the
IMAGESbinding puts a vector on an image, theTEXTbinding one on a document’s text, on/rmeta. -
T44/T45: the per-request switches,
text-recognizers.enabled: falseand aninference.bindingssubset, through/tika/configand/rmeta/config(allowPerRequestConfigis on in the inference config, so the T18 gating checks are skipped in this pass; the default-mode run covers them). -
T46: the
MEDIAbindings cut a 3 s clip into one segment per channel sharing a correlator. This needs ffmpeg on the server: a hard failure withTIKA_UAT_REQUIRE_MEDIA=1(the-fullimage ships it), a skip otherwise. -
T47: the mock’s
/stats(reached atTIKA_UAT_MOCK_URL, defaulthttp://localhost:18080) shows refusals, so the checks above passed only because the client retried. A mock started without--flakyreports no refusals and T47 is a skip.docker-tool.shand the e2e test start it flaky only when the server under test carries the retry (TIKA-4912), detected from itstika-http-jdkjar;TIKA_UAT_MOCK_FLAKY=1or=0overrides that in the tool.
The config names the engine key as ${env:TIKA_UAT_MOCK_KEY}, so the pass also proves
environment interpolation reaches the forked workers. docker-tool.sh test-uat runs this
pass against both images after the default-mode run, with the mock on the host and the
container reaching it as host.docker.internal; the RunUatSmokeTest e2e test runs it
against a forked java -jar server.
docker-tool.sh test-uat-snapshot builds the two images the docker-snapshot workflow
publishes, from Dockerfile.snapshot over this checkout’s tika-server-standard zip, and
runs both passes against each. No download and no signature check, so it works on any
build, and what it tests is the image itself: that is how the full image’s ffmpeg is
verified before a release, and it is the run that showed the snapshot Dockerfile had
been missed when ffmpeg was added to the release one.
The allowPipes=false "refuse to start" gating and the stale-enableUnsecureFeatures
upgrade behavior are start-time properties, so they are not in this script (which runs
against an already-running server) — they are covered by the
org.apache.tika.server.e2e.RunUatSmokeTest e2e test instead.
Running it
The script takes a URL pointing at a running tika-server. It does not start or stop the server itself.
release-tools/uat/run-uat.sh [base-url]
# default: http://localhost:9998
Exit code: 0 on all-pass, 1 on any failure. Failed checks print the
expected pattern and a truncated response body.
Against the unpacked server distribution zip
unzip tika-server-standard-<VERSION>.zip -d /tmp/tika-server-dist
cd /tmp/tika-server-dist
java -jar tika-server-standard-<VERSION>.jar -p 9998 -h localhost &
sleep 12
<tika-checkout>/release-tools/uat/run-uat.sh
Against the Docker image
The docker-tool.sh test-uat subcommand wraps starting each container, waiting
for /version, running the UAT, and stopping the container. It runs against both
the minimal and the -full image:
cd tika-server/docker-build
./docker-tool.sh test-uat <DOCKER_VERSION>
As part of the e2e tests (CI)
The Maven module tika-e2e-tests/tika-server unpacks the distribution zip, forks
java -jar tika-server-standard-<VERSION>.jar, and invokes this script via
org.apache.tika.server.e2e.RunUatSmokeTest. The CI workflow
.github/workflows/main-jdk17-build.yml runs it on pull requests to main (its
e2e-tests job installs the full reactor, then runs
mvn -pl :tika-e2e-tests-server,:tika-grpc-e2e-test clean verify -Pe2e). -pl must
name the leaf modules: tika-e2e-tests is an aggregator pom, and Maven does not pull
in a selected aggregator’s children.
When to use it
-
Pre-vote release verification. Unpack
tika-server-standard-<VERSION>.zipfromdist/devand run the UAT against it. Catches packaging regressions before the vote thread starts. -
Pre-publish docker verification. Run via
docker-tool.sh test-uatafter building a new image and before tagging it for release. -
Local development sanity check. When changing anything in
tika-server-coreor the server assembly descriptor, run the UAT against the build output to confirm you didn’t regress endpoint behavior. -
Adding new endpoints. When a new REST endpoint lands, add a corresponding check to the script so future regressions get caught.