Skip to main content
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

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

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

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

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

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

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

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:
    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.