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

# Test and validate

> Build the connector, run it locally, deploy with kamel:dev, and write SDK-based unit tests

Test and validate a Grand Central connector before you deploy it. The same connector codebase runs three ways during development: as a standard Maven build, as a Quarkus dev-mode app, and as a Camel-K integration on a cluster. The Grand Central SDK provides base classes that cover the common unit-test patterns.

## Build

```shell theme={"system"}
mvn clean verify
```

This compiles the connector, runs unit tests, generates the REST DSL from the OpenAPI spec, and packages the Quarkus app and Helm chart under `target/`.

## Run locally as a Quarkus app

```shell theme={"system"}
mvn quarkus:dev
```

Quarkus dev mode gives you:

* The Grand Central REST API served on `http://localhost:8080/*`
* Hot reload on Java and resource changes
* The Quarkus dev UI on `http://localhost:8080/q/dev/`

You can call the connector locally with `curl` or any REST client against `http://localhost:8080/<openapi-path>`.

## Run as a Camel-K integration on the cluster

```shell theme={"system"}
mvn kamel:dev
```

This packages the connector as a Camel-K integration and deploys it to the Kubernetes cluster your kubeconfig context selects. The `kamel-maven-plugin` and `maven-kamel-helm-plugin`, both inherited from `grandcentral-bom`, handle the manifest generation.

In `target/helm/` you find:

* `Chart.yaml`: generated chart metadata
* `values.yaml`: generated values, with placeholders matched by deploy-time overrides
* `connector/`: resource templates
* `templates/`: Helm templates

## Unit testing

All unit-test patterns build on `GrandCentralTestSupportUtil` and `JunitUtil` from `com.backbase.gc:grandcentral-connectors-sdk`, which the BOM manages. They cover the common cases, so there is no need to write your own base test classes or file-loading utilities.

### Pattern A: route integration test with AdviceWith and kamelet mocking

```java theme={"system"}
class {Vendor}{Domain}ConnectorTest extends GrandCentralTestSupportUtil {

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        {Vendor}{Domain}Connector connector = new {Vendor}{Domain}Connector();
        Properties props = useOverridePropertiesWithPropertiesComponent();
        for (Field field : connector.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(PropertyInject.class)) {
                field.setAccessible(true);
                PropertyInject annotation = field.getAnnotation(PropertyInject.class);
                String value = props.getProperty(annotation.value(),
                    annotation.defaultValue().isEmpty() ? null : annotation.defaultValue());
                if (value != null) field.set(connector, value);
            }
        }
        return connector;
    }

    @Override
    protected Properties useOverridePropertiesWithPropertiesComponent() {
        Properties p = new Properties();
        p.setProperty("{vendor}.base.url", "http://localhost:8080/mock");
        p.setProperty("retryFlag", "false");
        p.setProperty("acceptedHeaders", "entityId,Content-Type");
        p.setProperty("resourcesBasePath", "");
        return p;
    }

    @Override
    public void doPostSetup() throws Exception {
        JunitUtil.mockRoutes(context,
            List.of("direct://getEntityById", "direct://createEntity"),
            "kamelet:*");
        context.start();
    }

    @Test
    void getEntityById_shouldReturnMappedResponse() throws Exception {
        MockEndpoint mockKamelet = findMockKamelet();
        mockKamelet.whenAnyExchangeReceived(exchange ->
            exchange.getIn().setBody(JunitUtil.loadJsonFromResource("mock-entity-response.json")));

        Exchange result = template.send("direct://getEntityById",
            e -> e.getIn().setHeader("entityId", "ENTITY001"));

        assertNotNull(result.getIn().getBody(String.class));
        assertFalse(result.isFailed());
    }
}
```

### Pattern B: JOLT unit test with JsonString input

```java theme={"system"}
class {Op}{Entity}RequestTransformationTest {

    private static CamelContext context;
    private static ProducerTemplate template;
    private static final ObjectMapper MAPPER = new ObjectMapper();

    @BeforeAll
    static void setUp() throws Exception {
        context = new DefaultCamelContext();
        context.addRoutes(new RouteBuilder() {
            @Override public void configure() {
                from("direct:transform")
                    .to("jolt:{op}-{entity}-request-transformation.json"
                        + "?transformDsl=Chainr&inputType=JsonString&outputType=JsonString");
            }
        });
        context.start();
        template = context.createProducerTemplate();
    }

    @Test
    void shouldMapRequiredFields() throws Exception {
        String input = JunitUtil.loadJsonFromResource("test-{op}-{entity}-input.json").toString();
        String output = template.requestBody("direct:transform", input, String.class);
        Map<String, Object> result = MAPPER.readValue(output, new TypeReference<>() {});
        assertNotNull(result.get("vendorField"));
    }
}
```

### Pattern C: XSLT unit test

```java theme={"system"}
class {Op}{Entity}RequestTransformationTest {

    private static CamelContext context;
    private static ProducerTemplate template;

    @BeforeAll
    static void setUp() throws Exception {
        // Required for XSLT 3.0 (Saxon)
        System.setProperty("javax.xml.transform.TransformerFactory",
            "net.sf.saxon.TransformerFactoryImpl");
        context = new DefaultCamelContext();
        context.addRoutes(new RouteBuilder() {
            @Override public void configure() {
                from("direct:transform")
                    .to("xslt:{op}-{entity}-request-transformation.xslt");
            }
        });
        context.start();
        template = context.createProducerTemplate();
    }

    @Test
    void shouldProduceValidRequest() throws Exception {
        String input = JunitUtil.loadXmlFromResource("test-empty-root.xml");
        Exchange exchange = template.send("direct:transform", e -> {
            e.getIn().setBody(input);
            e.getIn().setHeader("entityId", "12345");
        });
        String output = exchange.getIn().getBody(String.class);
        assertNotNull(output);
        assertTrue(output.contains("12345"));
    }
}
```

### Run unit tests

```shell theme={"system"}
mvn test
mvn -Dtest=<ConnectorName>Test#<methodName> test
```

### Test fixture conventions

* `mock-{entity}-{scenario}-response.json` (or `.xml`): vendor-side fixture used to short-circuit the kamelet call.
* `test-{op}-{entity}-input.json`: request fixture for transformation unit tests.
* `expected-{op}-{entity}-response.json` (or `.xml`): golden file the route must produce.

## Namespace and cluster testing

For end-to-end testing against the actual vendor or a vendor mock, use the customer cluster. The cluster depends on the customer the connector targets. Follow the namespace setup runbook for your installation; each connector's README includes the canonical link.

The key steps are always:

1. Build and publish a SNAPSHOT image of the connector.
2. Update the matching `application-live` repository to bump the connector chart version and any `<<placeholder>>` values.
3. Trigger the namespace deploy pipeline for your assigned namespace.
4. Verify by hitting the Grand Central ingress with a REST client, Postman, or curl, and tail the connector pod logs:

   ```shell theme={"system"}
   kubectl logs -n <namespace> -l app=<connector>
   ```

## Next step

For the full list of Maven artifacts published to JFrog and the rules every connector must follow, see [Reference artifacts and rules](/platform/developer-guides/build/reference-artifacts-and-rules).
