> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chargerdojo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Test a roaming hub

> Register ChargerDojo with your OCPI roaming hub as one test party to check how the hub identifies itself, or as two parties to trace a Session and its error response through the hub.

A roaming hub sits between CPOs and eMSPs so each one integrates once. OCPI 2.2 gave hubs a
precise job: forward a request to the party it is addressed to, with the routing and message-id
headers the specification requires, leave the object untouched, and carry the receiver's answer
back. ChargerDojo checks that job against your own hub.

Before you register anything, open the
[reference hub sample](https://chargerdojo.com/ocpi-charging-journeys?sample=reference-hub). It is a
full relay report from our reference hub, a test peer we run that follows every rule below and does
nothing optional. Every plan can read it, signed in or not. Your report has the same shape, read from
your hub's own traffic.

## Which versions

Hub testing runs on OCPI 2.2, 2.2.1 and 2.3.0, the versions that define message routing.
OCPI 2.1.1 mentions hubs in its
[introduction](https://github.com/ocpi/ocpi/blob/28ea45329a50c3dbfd790505b97860854db1d4a6/introduction.md#introduction-and-background)
("A good roaming system (for bilateral usage and/or via a hub)") but has
no routing headers, no Role enum and no HubClientInfo module, so there is nothing in it for a hub
test to check.

## Check your hub's identity

Identity testing needs one registration and runs on Integrate.

1. In ChargerDojo, open **Endpoints**, choose **Add endpoint** and pick **Test a roaming hub**.
   The command palette entry **Test a roaming hub** opens the same form with the persona chosen.
2. Keep the mode on **Identity**. Enter your hub's base URL and its OCPI version. The form shows
   the exact versions URL we will ask for.
3. Enter your hub's own party. It is required on 2.3.0, where a hub names itself by
   `hub_party_id`.
4. Enter the CPO test party your hub provisioned for us and the registration token (Token A) it
   issued for that party, then **Register**.

When the registration completes, **Check identity** on the endpoint opens the identity journey. It
reads your hub's Credentials and watches the Configuration Module requests your hub sends us.

## Trace a relay between two test parties

Relay testing runs on Automate. We join your hub as two parties, a CPO and an eMSP, so a request
one sends can be watched arriving at the other.

1. In the same form, switch the mode to **Relay**.
2. Enter a CPO test party and an eMSP test party, each with the registration token your hub issued
   for it. The two parties must differ, and the pair uses two of your plan's endpoints.
3. **Register both**. Each side registers on its own. If one side fails, its row shows **Retry**
   beside it, and the healthy side stays registered.

**Test relay** on the endpoint runs the relay journey. Our CPO party sends a Session through your
hub to our eMSP party, sends an update for a Session the eMSP party never received so the error
response comes back through the hub, and addresses one request to a party your hub does not know.

Some hubs deliver between two parties only after a roaming agreement exists between them. On 2.2
and 2.2.1, when your hub's HubClientInfo list reports our eMSP party as anything other than
`CONNECTED`, the run sends no relay traffic and marks the relay checks unobservable with that
reason. Set up the agreement between the two
test parties, then run again.

Automate also schedules the relay. Open **Schedule** on the paired endpoint, choose **Hub relay**,
and every scheduled run re-reads both registrations and your current plan before it sends anything.
A schedule pauses itself when either registration goes away and resumes on its next slot once the
pair is back.

Certified covers many hubs and pairs under fair use, on a quote.

## What each check grades

Every hub journey check cites the clause it grades. These SHALL rules can fail your hub:

| Check | What it reads | Clause |
| - | - | - |
| U01 | The forwarded request names our eMSP party in `OCPI-to-*` and our CPO party in `OCPI-from-*`. | "When implementing OCPI these four headers SHALL be implemented for any request/response to/from a Functional Module." |
| U02 | Your hub's answer to our CPO party carries the same two parties the other way round. | Same clause, read on the response. |
| U03 | Each forwarded request carries a new `X-Request-ID`, and each response echoes its request's id. | "the request to this party SHALL contain a new unique value in the X-Request-ID HTTP header" |
| U04 | The forwarded request carries the `X-Correlation-ID` we sent, byte for byte. | "the request SHALL contain the same X-Correlation-ID HTTP header (with the same value)" |
| U05 | The forwarded Session keeps the `last_updated` instant we sent. | "the `last_updated` fields SHALL NOT be updated by the Hub" |
| U06 | The status code our eMSP party answered is the one our CPO party receives. | "The Hub SHALL then forward this error to the client which sent the request" |
| U07 | On 2.2 and 2.2.1, your hub's Credentials `roles` hold only role `HUB`. | "A Hub SHALL only reports itself as role: Hub." |
| U08 | On 2.2 and 2.2.1, your hub's HubClientInfo list is a list, and it names our other party. | "A Hub SHALL report connected parties via the HubClientInfo module." |
| U09 | On 2.3.0, your hub's Credentials carry a five-character `hub_party_id`. | "SHALL give the country code and party ID of the Hub in the `hub_party_id` field" |
| U10 | No Credentials, Versions or HubClientInfo request or response carries a routing header. | "Thus routing headers SHALL NOT be used with these modules." |

The quotes are from the OCPI 2.2.1 chapters
[Message routing](https://github.com/ocpi/ocpi/blob/ca8c04c5c8cc10ad1be2a82f61b19377d98e2a67/transport_and_format.asciidoc#transport_and_format_message_routing),
[Unique message IDs](https://github.com/ocpi/ocpi/blob/ca8c04c5c8cc10ad1be2a82f61b19377d98e2a67/transport_and_format.asciidoc#transport_and_format_unique_messageg_ids),
[Hub errors](https://github.com/ocpi/ocpi/blob/ca8c04c5c8cc10ad1be2a82f61b19377d98e2a67/status_codes.asciidoc#status_codes_4xxx_hub_errors) and
[Credentials](https://github.com/ocpi/ocpi/blob/ca8c04c5c8cc10ad1be2a82f61b19377d98e2a67/credentials.asciidoc#credentials_credentials_object). OCPI
[2.2](https://github.com/ocpi/ocpi/blob/0b53077d877d9f61815408554c2962b013f2536a/transport_and_format.asciidoc#transport_and_format_message_routing) and
[2.3.0](https://github.com/ocpi/ocpi/blob/9ed1e39c24f5b84cb1e4008939f47bea838f9b25/transport_and_format.asciidoc#transport_and_format_message_routing) print the
same routing, message-id and error text; the 2.3.0
[Credentials chapter](https://github.com/ocpi/ocpi/blob/9ed1e39c24f5b84cb1e4008939f47bea838f9b25/credentials.asciidoc#credentials_credentials_object) carries
`hub_party_id` where 2.2 and 2.2.1 carry the Hub role.

Party ids compare as case-insensitive strings, as their `CiString` type says. Message ids compare
byte for byte. `last_updated` compares as an instant, so `10:00:00Z` and `10:00:00.000Z` are the
same value.

U08 grades what the list proves. A list missing our other party is unobservable rather than failed,
because a party can be activated by the relay itself, and a later delivery proves nothing about an
earlier listing. An omitted, null or empty list is permitted. A list container that is present and
is not a list fails.

These three are observations. They appear in the report and never fail your hub:

| Check | What it reports | Why it never fails |
| - | - | - |
| U11 | A relayed request your hub answered with success that never reached our eMSP party. | No clause says a hub SHALL deliver. |
| U12 | The answer to a request addressed to an unknown party, expected as `4001`. | The 4xxx codes are written as "shall be used", lowercase. |
| U13 | On 2.3.0, whether `roles` lists the parties reachable through your hub. | The specification states it as a note. |

When a check's premise is missing, the check is unobservable and the report says why. A relay that
never reached our eMSP party makes U01 to U05 unobservable instead of failed, and the report shows
which hop was not observed.

## What hub testing leaves alone

Broadcast Push, Open Routing, GET All via Hubs, the HubClientInfo push and its still-alive check,
chains of hubs and commands through a hub are optional for a hub or not tied to it by any clause, so
no check grades them. A Gireve or Plugsurfing Roam profile is a partner expectation and never a
specification verdict.

## Learn the terms

The [Learning Hub's key terminology](https://chargerdojo.com/learn/key-terminologies/) explains
what a hub is in OCPI, the Explorer walks the
[Credentials](https://chargerdojo.com/learn/explorer/credentials/) and
[HubClientInfo](https://chargerdojo.com/learn/explorer/hubclientinfo/) modules, and the
[Payload Workbench](https://chargerdojo.com/ocpi-testing-tool/payload-workbench) checks a single
Session or Credentials object in the browser. None of them sends traffic through your hub, so only the
journeys above test delivery.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.