# Plugin Overview

> Extend KTestify with plugins, mechanisms, plugin marketplace, and building your own transports.

Source: https://docs.ktestify.xyz/docs/extend/plugins

KTestify's plugin system makes it easy to extend the framework with new transports, storage backends, and integrations, all without modifying core code. Plugins are discovered automatically at startup and contribute Cucumber steps that users can call in their Gherkin scenarios.

---

## What Plugins Can Do

1. **Add new transports**, IBM MQ, Amazon SQS, MQTT, NATS, etc. alongside Kafka
2. **Integrate external services**, Azure Blob Storage, AWS S3, SFTP servers, databases
3. **Add custom assertions**, domain-specific validation logic
4. **Contribute reusable steps**, ready-to-use Cucumber step definitions

All without modifying any core ktestify code.

---

## How Plugins Work (30-second overview)

1. **Implement `KtestifyPlugin`** interface, define your plugin ID, version, and glue package
2. **Place configuration** under `ktestify.plugins.<id>` in HOCON
3. **Write Cucumber steps** in the glue package you declared
4. **Register via SPI**, add a single line to `META-INF/services/io.github.ktestify.plugin.KtestifyPlugin`
5. **Plugins auto-discover** at startup via `ServiceLoader` or from `/workspace/plugins` directory

Done! Your plugin is now available in any ktestify test run.

---

## In This Section

### [Plugin System Documentation](plugin-system)

Deep dive into,

- How the two-phase plugin loading works (classpath, then external directory)
- Lifecycle of plugins (discovery, initialization, execution, shutdown)
- Core interfaces (`KtestifyPlugin`, `PluginContext`, `PluginRegistry`)
- Configuration via HOCON
- Startup diagnostics and troubleshooting

**Read this if**: You want to understand *how* ktestify's plugin system works or need to debug plugin loading.

### [Creating a Plugin](create-plugin)

Complete step-by-step guide covering,

- Project setup using the Maven archetype (`ktestify-plugin-archetype`)
- Archetype parameters and project generation
- Implementing `KtestifyPlugin` with proper initialization and shutdown
- Building the transport layer (`RecordFetcher` implementation)
- Writing Cucumber step definitions
- Configuration and SPI registration
- Testing with Testcontainers
- Production checklist

**Read this if**: You want to build your own plugin or learn by example.

### [Azure Blob Storage Plugin](azureblob)

Reference documentation for the `ktestify-plugin-azureblob` first-party plugin,

- Installation as Maven dependency or Docker JAR
- Complete configuration reference
- All Gherkin step definitions with examples
- Local development with Azurite emulator
- Three-layer architecture overview
- Troubleshooting common issues

**Read this if**: You want to use the Azure Blob plugin or see a real-world example.

---

## Quick Start

### Use an Existing Plugin

1. Add the plugin JAR as a Maven dependency
2. Add configuration to your `application.conf` under `ktestify.plugins.<id>`
3. Use the plugin's steps in your Gherkin scenarios
4. Run your tests, plugin auto-discovers at startup

Example with Azure Blob Plugin,

```xml
<!-- pom.xml -->
<dependency>
    <groupId>io.github.ktestify</groupId>
    <artifactId>ktestify-plugin-azureblob</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <scope>test</scope>
</dependency>
```

```hocon
# application.conf
ktestify.plugins.azure-blob {
  connection-string = ${?AZURE_STORAGE_CONNECTION_STRING}
}
```

```gherkin
# orders.feature
Given Azure Blob container
  | containerName | containerAlias |
  | test-output   | blobs          |

Then expected blob from file
  | containerAlias | blobName | file        |
  | blobs          | data.json| expected.json|
```

### Build Your Own Plugin

Start with the Maven archetype, which generates a complete, compilable project in seconds:

```bash
mvn archetype:generate \
  -DarchetypeGroupId=io.github.ktestify \
  -DarchetypeArtifactId=ktestify-plugin-archetype \
  -DarchetypeVersion=1.0-SNAPSHOT \
  -DgroupId=io.github.ktestify \
  -DartifactId=ktestify-plugin-myplugin \
  -Dversion=1.0-SNAPSHOT \
  -Dpackage=io.github.ktestify.myplugin \
  -DpluginShortName=myplugin \
  -DpluginKebabId=my-plugin \
  -DpluginPascalName=MyPlugin \
  -DinteractiveMode=false
```

Then follow the [Creating a Plugin](create-plugin) guide to implement your transport logic.

---

## Available Plugins

| Plugin | Status | Purpose |
|---|---|---|
| **Azure Blob Storage** | 🚧 In progress | Upload/download/validate files in Azure Blob Storage |
| **Notifications** | 🚧 In progress | Send suite summary cards to Teams, Slack, or any HTTP webhook |
| **S3** | 💡 Planned | Amazon S3 integration |
| **IBM MQ** | 💡 Planned | IBM Message Queue transport |
| **SFTP** | 💡 Planned | SFTP file transfer validation |

:::tip
Don't see a plugin you need? [Build your own!](create-plugin)
:::

---

## Plugin Architecture

Every plugin follows the same three-layer separation as ktestify-core,

```
┌────────────────────────────────────────────────────────────┐
│  TRANSPORT LAYER              │  ORCHESTRATION  │ ASSERTION │
│  RecordFetcher<V> impl        │  Consumer       │ Matcher   │
│  (plugin provides)            │  (plugin wires) │ (reuse)   │
└────────────────────────────────────────────────────────────┘
```

- **Transport**, Your plugin implements `RecordFetcher<V>` to fetch records from the external system
- **Orchestration**, Consumer classes wire fetch, decrypt, and pass to matchers
- **Assertion**, Reuse ktestify-core's standard `RecordMatcher` implementations

This separation means,

- Adding a new transport does *not* require new matcher logic
- Existing matchers automatically work with new transports
- Plugins stay focused and maintainable

---

## Plugin Lifecycle

1. **JVM Start**, ktestify initializes config, then discovers plugins
2. **Classpath Phase**, `ServiceLoader` finds plugins on classpath (from Maven deps)
3. **External Phase**, Scans `/workspace/plugins` or configured directory for external JARs
4. **Initialize**, Each plugin's `initialize(PluginContext)` is called once (in discovery order)
5. **Scenario Runs**, Cucumber runs scenarios, steps from plugins are available
6. **Shutdown**, Each plugin's `shutdown()` is called once (reverse initialization order)

If any plugin's `initialize()` fails, the entire test run aborts with `PluginException`.

---

## Best Practices

1. **Use consistent IDs**, kebab-case like `azure-blob`, `ibm-mq` (not camelCase or UPPER_CASE)
2. **Namespace config**, always use `ktestify.plugins.<id>` to avoid conflicts
3. **Validate early**, fail in `initialize()` if critical config is missing
4. **Release resources**, close connections and stop threads in `shutdown()`
5. **Log diagnostics**, use SLF4J so users can troubleshoot plugin loading
6. **Document thoroughly**, include config examples, step definitions, and usage scenarios
7. **Use the archetype**, start from `ktestify-plugin-archetype` to get the correct structure and build setup
8. **Write tests**, unit tests for config parsing, integration tests with Docker

---

## Troubleshooting Plugins

### Plugin Not Loading

Check the startup log for the plugin system banner,

```
╔══ KTestify Plugin System ═════════════════════════════════════
║  [classpath] Discovered plugin: azure-blob v1.0 ...
║  2 plugin(s) active: [azure-blob@1.0, ibm-mq@1.5]
╚═══════════════════════════════════════════════════════════════
```

If your plugin is missing,

- On classpath? Verify JAR is included and `META-INF/services/io.github.ktestify.plugin.KtestifyPlugin` exists
- External JAR? Check that `/workspace/plugins` (or `ktestify.plugins.dir`) contains the JAR
- Run with `-Dorg.slf4j.simpleLogger.defaultLogLevel=debug` for detailed discovery logs

### Plugin Initialization Failed

```
io.github.ktestify.exceptions.PluginException:
  Plugin 'my-plugin' failed to initialize: Connection timeout
```

Check,

- Is configuration present? Verify `ktestify.plugins.<id>` exists in config
- Are credentials valid? Check environment variables or `application.conf`
- Is the external service reachable? Test connectivity before running tests

### Steps Not Discovered

If steps from your plugin aren't available,

- Verify `getGluePackage()` returns the correct package name
- Check that step classes are in that exact package
- Verify steps use `@Given`, `@When`, `@Then` from `io.cucumber.java.en`

---

## Next Steps

- Learn [how plugins work](plugin-system)
- [Build your first plugin](create-plugin) with the Maven archetype
- Explore the [Azure Blob reference](azureblob)
- Send results with the [Notifications reference](notifications)
- Check out the [plugin archetype](https://github.com/ktestify/ktestify-plugin-archetype)
