JUnit Parse
quality.junit_parse
Overview
You send JUnit XML inline or as a tenant-owned file_ref, at most 25 MiB. dialect defaults to AUTO and may be JUNIT4, JUNIT5, SUREFIRE or GRADLE. includeSystemOutput defaults to false; when true, system-out and system-err snippets are capped at 16 KiB per suite. DOCTYPE and external entities are refused. This does not execute tests.
JUnit XML dialects share a shape; a hardened StAX reader turns them into one model without entity expansion.
Reliability
DOCTYPE and external entities are refused. Snippets clip at 16384 characters. JUNIT_XML_INVALID — trigger: XML that is not well-formed JUnit; retryable: no; next: send a testsuite document. JUNIT_XML_UNSAFE — trigger: a DOCTYPE or DTD event; retryable: no; next: send XML without a DTD. JUNIT_XML_LIMIT_EXCEEDED — trigger: more than 25 MiB, 64 nested elements or 10000 cases; retryable: no; next: split the report.
Context footprint
Names, statuses and bounded snippets only. A successful call costs 2 execution credits.
When to use it
When a JUnit, Surefire or Gradle XML report must be normalized.
When the report is already JSON, or when tests still need running.
Powered by a hardened JDK StAX reader with DTD and external entities disabled.
Scope
Non-goals
- Does not execute tests
- Does not fetch attachments
- Does not parse arbitrary XML
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
File limits
Constraints this skill applies to your input and generated files. The “Limited by” column shows the static source of each cap; none of these can be raised by upgrading your plan.
| Limit | Value | Limited by |
|---|---|---|
| Maximum size per input file | 25 MiB | Skill and platform maximum |
How we handle your data
What this means
This skill is designed to detect, mask, redact, validate, or otherwise process sensitive data.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- Targets sensitive data
- The response does not contain submitted content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| source | object | Yes | Closed XML source: type inline with content, or type file_ref with a tenant-owned ref. |
| dialect | string | No | AUTO, JUNIT4, JUNIT5, SUREFIRE or GRADLE; omit it for AUTO detection from the XML. |
| includeSystemOutput | boolean | No | When true, keep 16 KiB system-out and system-err snippets per suite; omit it for false. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| dialect | string | Yes | Dialect that was actually applied after AUTO detection. |
| requestedDialect | string | Yes | Dialect that was requested, including AUTO. |
| suites | array | Yes | Normalized suites in document order, 1 through 10000 closed suite objects with name, cases and per-suite counts. |
| totals | object | Yes | Closed aggregate tests, passed, failed, skipped and errors counts. |
| diagnostics | array | Yes | Parse notes in a stable order; empty when the document was accepted as-is. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"quality.junit_parse","input":{"source":{"type":"inline","content":"<testsuite name=\"BillingSuite\"><testcase name=\"ok\" time=\"0.01\"/></testsuite>"}}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("quality.junit_parse", {"source":{"type":"inline","content":"<?xml version=\"1.0\"?>\n<testsuite name=\"BillingSuite\" tests=\"2\" failures=\"1\" time=\"0.016\">\n <testcase name=\"chargesInvoice\" classname=\"BillingTest\" time=\"0.012\"/>\n <testcase name=\"rejectsVoid\" classname=\"BillingTest\" time=\"0.004\">\n <failure message=\"expected 402\">AssertionError</failure>\n </testcase>\n</testsuite>\n"}});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| JUNIT_XML_INVALID | 400 | No | The request payload failed this skill's input validation. |
| JUNIT_XML_UNSAFE | 400 | No | The request payload failed this skill's input validation. |
| JUNIT_XML_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not execute tests
- Does not fetch attachments
- Does not parse arbitrary XML
- Executing the suite
- Parsing a coverage XML report
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "quality.junit_parse",
"input": {
"source": {
"type": "inline",
"content": "<?xml version=\"1.0\"?>\n<testsuite name=\"BillingSuite\" tests=\"2\" failures=\"1\" time=\"0.016\">\n <testcase name=\"chargesInvoice\" classname=\"BillingTest\" time=\"0.012\"/>\n <testcase name=\"rejectsVoid\" classname=\"BillingTest\" time=\"0.004\">\n <failure message=\"expected 402\">AssertionError</failure>\n </testcase>\n</testsuite>\n"
}
}
}Examples
A suite with one pass and one failure totals two tests
{
"source": {
"type": "inline",
"content": "<?xml version=\"1.0\"?>\n<testsuite name=\"BillingSuite\" tests=\"2\" failures=\"1\" time=\"0.016\">\n <testcase name=\"chargesInvoice\" classname=\"BillingTest\" time=\"0.012\"/>\n <testcase name=\"rejectsVoid\" classname=\"BillingTest\" time=\"0.004\">\n <failure message=\"expected 402\">AssertionError</failure>\n </testcase>\n</testsuite>\n"
}
}{
"totals": {
"tests": 2,
"passed": 1,
"failed": 1,
"skipped": 0,
"errors": 0
},
"dialect": "JUNIT4",
"diagnostics": [],
"suites": [
{
"name": "BillingSuite",
"cases": [
{
"name": "chargesInvoice",
"className": "BillingTest",
"status": "PASSED",
"durationMs": 12
},
{
"name": "rejectsVoid",
"className": "BillingTest",
"status": "FAILED",
"durationMs": 4,
"message": "expected 402",
"stack": "AssertionError"
}
],
"tests": 2,
"passed": 1,
"failed": 1,
"skipped": 0,
"errors": 0
}
],
"requestedDialect": "AUTO"
}A skipped testcase maps to SKIPPED
{
"source": {
"type": "inline",
"content": "<?xml version=\"1.0\"?>\n<testsuite name=\"SkipSuite\" tests=\"1\" skipped=\"1\" time=\"0\">\n <testcase name=\"ignoredOnCi\" classname=\"SkipTest\" time=\"0\">\n <skipped message=\"not on CI\"/>\n </testcase>\n</testsuite>\n"
}
}{
"totals": {
"tests": 1,
"passed": 0,
"failed": 0,
"skipped": 1,
"errors": 0
},
"dialect": "JUNIT4",
"diagnostics": [],
"suites": [
{
"name": "SkipSuite",
"cases": [
{
"name": "ignoredOnCi",
"className": "SkipTest",
"status": "SKIPPED",
"durationMs": 0,
"message": "not on CI"
}
],
"tests": 1,
"passed": 0,
"failed": 0,
"skipped": 1,
"errors": 0
}
],
"requestedDialect": "AUTO"
}Recommended use cases
- Turn a Surefire XML file into stable statuses
- Read a skipped JUnit case
Avoid for
- Executing the suite
- Parsing a coverage XML report
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.