Azure Blob Storage Plugin
ktestify-plugin-azureblob is a first-party KTestify plugin that integrates Azure Blob Storage into your Kafka testing workflows. It allows you to upload blobs as test fixtures before producing Kafka messages, and assert that your pipeline correctly wrote output blobs.
This plugin is actively being developed. The API surface, step definitions, and configuration keys may evolve before the first stable release.
When to Useโ
Use the Azure Blob plugin when your system,
- Reads input files from Azure Blob Storage before processing Kafka messages
- Writes result files to Azure Blob Storage after consuming Kafka topics
- Needs to validate blob content as part of end-to-end test scenarios
- Must test Azure Storage and Kafka integration together
Installationโ
Maven Dependencyโ
<dependency>
<groupId>io.github.ktestify</groupId>
<artifactId>ktestify-plugin-azureblob</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
With ktestify-cucumber (Docker)โ
Drop the plugin JAR into /workspace/plugins and ktestify will auto-discover it via ServiceLoader,
docker run --rm \
-v $(pwd)/features:/workspace/features \
-v $(pwd)/assets:/workspace/assets \
-v $(pwd)/plugins:/workspace/plugins \
-e AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=..." \
ghcr.io/ktestify/ktestify-cucumber:latest \
/workspace/features
Configurationโ
The plugin reads settings from ktestify.plugins.azure-blob in your HOCON configuration file. Place your configuration in application.conf or override via environment variables.
Configuration Keysโ
ktestify.plugins.azure-blob {
# Connection string (primary, recommended)
# Takes precedence over SAS token or account key approaches
connection-string = "DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net"
connection-string = ${?AZURE_STORAGE_CONNECTION_STRING}
# Alternatively: SAS token (when connection-string is not set)
sas-token = ""
sas-token = ${?AZURE_STORAGE_SAS_TOKEN}
# Storage account endpoint (required when using SAS or managed identity)
endpoint = "https://myaccount.blob.core.windows.net"
endpoint = ${?AZURE_STORAGE_ENDPOINT}
# Timeout for individual blob operations (upload, download, list)
request-timeout = 30s
request-timeout = ${?KTESTIFY_AZURE_BLOB_REQUEST_TIMEOUT}
# Automatically create containers if they don't exist
auto-create-containers = true
auto-create-containers = ${?KTESTIFY_AZURE_BLOB_AUTO_CREATE}
}
Configuration Priorityโ
- System properties (e.g.
-Dktestify.plugins.azure-blob.connection-string=...) - Environment variables (e.g.
AZURE_STORAGE_CONNECTION_STRING) application.confin classpath- Plugin's
reference.conf(defaults)
Gherkin Stepsโ
Background, Register a Blob Containerโ
Before using the Azure Blob steps, register a container with an alias in your scenario background,
Background:
Given Azure Blob container
| containerName | containerAlias |
| test-inputs | input-blobs |
| test-outputs | output-blobs |
| Column | Description |
|---|---|
containerName | Actual Azure container name |
containerAlias | Alias used in later steps (e.g. input-blobs) |
Action, Upload a Blob from Fileโ
Upload a local file to Azure Blob Storage before running your action,
When blob from file is uploaded
| containerAlias | blobName | file | tags |
| input-blobs | orders/order.json| order.json | env=test,type=order |
| Column | Description | Optional |
|---|---|---|
containerAlias | The registered container alias | No |
blobName | Target blob path in container | No |
file | Local file path (relative to assets dir) | No |
tags | Blob tags as key=value pairs (comma-separated) | Yes |
Validation, Assert Blob Contentโ
Validate that a blob exists and matches expected content,
Then expected blob from file
| containerAlias | blobName | file | readTimeout |
| output-blobs | orders/order.json | expected.json | 30 |
| Column | Description | Optional |
|---|---|---|
containerAlias | The registered container alias | No |
blobName | Blob path to validate | No |
file | Expected file path (relative to assets dir) | No |
readTimeout | How long to wait for blob to appear (seconds) | Yes, default 30 |
Negative Assertion, Assert Blob Does Not Existโ
And blob should not exist
| containerAlias | blobName |
| output-blobs | orders/error-file.json|
Complete Scenario Exampleโ
Feature: Order processor writes results to Azure Blob
Background:
Given namespace
| namespace |
| test-namespace |
Given input topic
| topicName | topicAlias |
| orders-in | orders |
Given output topic
| topicName | topicAlias |
| orders-out | results |
Given Azure Blob container
| containerName | containerAlias |
| inputs | input-blobs |
| outputs | output-blobs |
Given assets directory
| absolutePath |
| src/test/resources/data |
Scenario: Process order and write result blob
Given blob from file is uploaded
| containerAlias | blobName | file |
| input-blobs | order-001.json | order.json |
When record from file is sent
| topicName | file | recordKey |
| orders-in | order-trigger.json| ORD-001 |
And wait for 5 seconds
Then expected record from file
| topicName | file |
| orders-out| order-result.json |
And expected blob from file
| containerAlias | blobName | file |
| output-blobs | order-001-result | expected-blob.json|
Local Development with Azuriteโ
For local testing and CI/CD, use the Azurite emulator instead of a real Azure account,
Start Azuriteโ
docker run -p 10000:10000 mcr.microsoft.com/azure-storage/azurite azurite-blob --loose
Configure for Local Testingโ
Add this to your test application.conf,
ktestify.plugins.azure-blob {
connection-string = "UseDevelopmentStorage=true"
}
Or set the environment variable,
export AZURE_STORAGE_CONNECTION_STRING="UseDevelopmentStorage=true"
The plugin will automatically use the local Azurite instance running on 127.0.0.1:10000.
Implementation Structureโ
The plugin follows the three-layer architecture defined by ktestify-core,
ktestify-plugin-azureblob/
โโโ src/main/java/io/github/ktestify/azureblob/
โโโ AzureBlobPlugin.java โ KtestifyPlugin SPI impl
โโโ config/
โ โโโ AzureBlobConfig.java โ reads ktestify.plugins.azure-blob HOCON
โโโ entities/
โ โโโ KtestifyBlobContainer.java โ container metadata model
โโโ io/
โ โโโ AzureBlobClient.java โ Azure SDK wrapper (lifecycle)
โ โโโ AzureBlobRecordFetcher.java โ implements RecordFetcher<String>
โโโ services/
โ โโโ BlobUploadService.java โ upload logic
โ โโโ BlobValidationService.java โ content matching
โโโ steps/
โโโ AzureBlobBackgroundSteps.java
โโโ AzureBlobActionSteps.java
โโโ AzureBlobValidationSteps.java
โโโ SharedAzureBlobResources.java โ scenario-scoped state
Key layers :
- Transport,
AzureBlobRecordFetcherimplementsRecordFetcher<String>and polls Azure Blob Storage - Orchestration, Service classes wire upload, fetch, and validation
- Assertion, Reuses standard
RecordMatcherimplementations from ktestify-core
Error Handlingโ
Container Does Not Existโ
If auto-create-containers = true (default), the plugin automatically creates missing containers. Otherwise,
io.github.ktestify.exceptions.PluginException:
Container 'test-inputs' does not exist.
Set auto-create-containers=true or create it manually.
Authentication Failedโ
io.github.ktestify.exceptions.PluginException:
Azure Blob authentication failed.
Verify AZURE_STORAGE_CONNECTION_STRING or credentials in config.
Blob Not Foundโ
If a blob is not found within readTimeout,
AssertionError: Blob not found within 30s: orders/order.json
Check that,
- The container name and blob path are correct
- The previous step that was supposed to create the blob ran successfully
- The timeout value is sufficient for your system's latency
Advanced Topicsโ
Dynamic Blob Namesโ
Use ktestify's dynamic variable syntax in blob names,
Then expected blob from file
| containerAlias | blobName | file |
| output-blobs | {{env:ORDER_ID}}/result-{{date}}.json | expected.json|
See Dynamic Variables for the full syntax.
Accessing Created Blobs in Codeโ
If you need to access blob data from Java test code,
@Inject SharedAzureBlobResources resources;
@Test
public void myTest() {
// Upload
resources.uploadBlob("input-blobs", "test.json", new File("payload.json"));
// Download
String content = resources.downloadBlobAsString("output-blobs", "result.json");
assertThat(content).contains("expected-value");
}
Troubleshootingโ
| Issue | Solution |
|---|---|
| Plugin not discovered | Ensure JAR is in classpath or /workspace/plugins, check logs for ServiceLoader errors |
| "Container does not exist" | Set auto-create-containers = true or create the container in Azure Portal |
| Timeout waiting for blob | Increase readTimeout parameter or check that the producing system wrote the blob |
| "Invalid connection string" | Verify the format, use DefaultEndpointsProtocol=https;... for real Azure or UseDevelopmentStorage=true for Azurite |
Contributingโ
The Azure Blob plugin is actively maintained. Report issues and contribute improvements at,
ktestify-plugin-azureblob on GitHub
See Alsoโ
- Plugin System Overview, how plugins work
- Creating a Plugin, build your own plugin from scratch
- ktestify-core Docs, transport and matcher internals