Skip to content
Kong Docs are moving soon! Our docs are migrating to a new home. You'll be automatically redirected to the new site in the future. In the meantime, view this page on the new site!
Kong Logo | Kong Docs Logo
  • Docs
    • Explore the API Specs
      View all API Specs View all API Specs View all API Specs arrow image
    • Documentation
      API Specs
      Kong Gateway
      Lightweight, fast, and flexible cloud-native API gateway
      Kong Konnect
      Single platform for SaaS end-to-end connectivity
      Kong AI Gateway
      Multi-LLM AI Gateway for GenAI infrastructure
      Kong Mesh
      Enterprise service mesh based on Kuma and Envoy
      decK
      Helps manage Kong’s configuration in a declarative fashion
      Kong Ingress Controller
      Works inside a Kubernetes cluster and configures Kong to proxy traffic
      Kong Gateway Operator
      Manage your Kong deployments on Kubernetes using YAML Manifests
      Insomnia
      Collaborative API development platform
  • Plugin Hub
    • Explore the Plugin Hub
      View all plugins View all plugins View all plugins arrow image
    • Functionality View all View all arrow image
      View all plugins
      AI's icon
      AI
      Govern, secure, and control AI traffic with multi-LLM AI Gateway plugins
      Authentication's icon
      Authentication
      Protect your services with an authentication layer
      Security's icon
      Security
      Protect your services with additional security layer
      Traffic Control's icon
      Traffic Control
      Manage, throttle and restrict inbound and outbound API traffic
      Serverless's icon
      Serverless
      Invoke serverless functions in combination with other plugins
      Analytics & Monitoring's icon
      Analytics & Monitoring
      Visualize, inspect and monitor APIs and microservices traffic
      Transformations's icon
      Transformations
      Transform request and responses on the fly on Kong
      Logging's icon
      Logging
      Log request and response data using the best transport for your infrastructure
  • Support
  • Community
  • Kong Academy
Get a Demo Start Free Trial
Kong Gateway
3.9.x
  • Home icon
  • Kong Gateway
  • Plugin Development
  • Get Started
  • Add Plugin Testing
github-edit-pageEdit this page
report-issueReport an issue
  • Kong Gateway
  • Kong Konnect
  • Kong Mesh
  • Kong AI Gateway
  • Plugin Hub
  • decK
  • Kong Ingress Controller
  • Kong Gateway Operator
  • Insomnia
  • Kuma

  • Docs contribution guidelines
  • 3.10.x (latest)
  • 3.9.x
  • 3.8.x
  • 3.7.x
  • 3.6.x
  • 3.5.x
  • 3.4.x (LTS)
  • 3.3.x
  • 2.8.x (LTS)
  • Archive (3.0.x and pre-2.8.x)
  • Introduction
    • Overview of Kong Gateway
    • Support
      • Version Support Policy
      • Third Party Dependencies
      • Browser Support
      • Vulnerability Patching Process
      • Software Bill of Materials
    • Stability
    • Release Notes
    • Breaking Changes
      • Kong Gateway 3.9.x
      • Kong Gateway 3.8.x
      • Kong Gateway 3.7.x
      • Kong Gateway 3.6.x
      • Kong Gateway 3.5.x
      • Kong Gateway 3.4.x
      • Kong Gateway 3.3.x
      • Kong Gateway 3.2.x
      • Kong Gateway 3.1.x
      • Kong Gateway 3.0.x
      • Kong Gateway 2.8.x or earlier
    • Key Concepts
      • Services
      • Routes
      • Consumers
      • Upstreams
      • Plugins
      • Consumer Groups
    • How Kong Works
      • Routing Traffic
      • Load Balancing
      • Health Checks and Circuit Breakers
    • Glossary
  • Get Started with Kong
    • Get Kong
    • Services and Routes
    • Rate Limiting
    • Proxy Caching
    • Key Authentication
    • Load-Balancing
  • Install Kong
    • Overview
    • Kubernetes
      • Overview
      • Install Kong Gateway
      • Configure the Admin API
      • Install Kong Manager
    • Docker
      • Using docker run
      • Build your own Docker images
    • Linux
      • Amazon Linux
      • Debian
      • Red Hat
      • Ubuntu
    • Post-installation
      • Set up a data store
      • Apply Enterprise license
      • Enable Kong Manager
  • Kong in Production
    • Deployment Topologies
      • Overview
      • Kubernetes Topologies
      • Hybrid Mode
        • Overview
        • Deploy Kong Gateway in Hybrid mode
      • DB-less Deployment
      • Traditional
    • Running Kong
      • Running Kong as a non-root user
      • Securing the Admin API
      • Using systemd
    • Access Control
      • Start Kong Gateway Securely
      • Programatically Creating Admins
      • Enabling RBAC
    • Licenses
      • Overview
      • Download your License
      • Deploy Enterprise License
      • Using the License API
      • Monitor Licenses Usage
    • Networking
      • Default Ports
      • DNS Considerations
      • Network and Firewall
      • CP/DP Communication through a Forward Proxy
      • PostgreSQL TLS
        • Configure PostgreSQL TLS
        • Troubleshooting PostgreSQL TLS
    • Kong Configuration File
    • Environment Variables
    • Serving a Website and APIs from Kong
    • Monitoring
      • Overview
      • Prometheus
      • StatsD
      • Datadog
      • Health Check Probes
      • Expose and graph AI Metrics
    • Tracing
      • Overview
      • Writing a Custom Trace Exporter
      • Tracing API Reference
    • Resource Sizing Guidelines
    • Blue-Green Deployments
    • Canary Deployments
    • Clustering Reference
    • Performance
      • Performance Testing Benchmarks
      • Establish a Performance Benchmark
      • Improve performance with Brotli compression
    • Logging and Debugging
      • Log Reference
      • Dynamic log level updates
      • Customize Gateway Logs
      • Debug Requests
      • AI Gateway Analytics
    • Configure a gRPC service
    • Use the Expressions Router
    • Upgrade and Migration
      • Upgrading Kong Gateway 3.x.x
      • Backup and Restore
      • Upgrade Strategies
        • Dual-Cluster Upgrade
        • In-Place Upgrade
        • Blue-Green Upgrade
        • Rolling Upgrade
      • Upgrade from 2.8 LTS to 3.4 LTS
      • Migrate from OSS to Enterprise
      • Migration Guidelines Cassandra to PostgreSQL
      • Migrate to the new DNS client
      • Breaking Changes
  • Kong Gateway Enterprise
    • Overview
    • Secrets Management
      • Overview
      • Getting Started
      • Secrets Rotation
      • Advanced Usage
      • Backends
        • Overview
        • Environment Variables
        • AWS Secrets Manager
        • Azure Key Vaults
        • Google Cloud Secret Manager
        • HashiCorp Vault
      • How-To
        • Securing the Database with AWS Secrets Manager
      • Reference Format
    • Dynamic Plugin Ordering
      • Overview
      • Get Started with Dynamic Plugin Ordering
    • Audit Logging
    • Keyring and Data Encryption
    • Workspaces
    • Consumer Groups
    • Event Hooks
    • Configure Data Plane Resilience
    • About Control Plane Outage Management
    • FIPS 140-2
      • Overview
      • Install the FIPS Compliant Package
    • Authenticate your Kong Gateway Amazon RDS database with AWS IAM
    • Verify Signatures for Signed Kong Images
    • Verify Build Provenance for Signed Kong Images
    • Datakit
      • Overview
      • Get Started with Datakit
      • Datakit Configuration Reference
      • Datakit Examples Reference
  • Kong AI Gateway
    • Overview
    • Get started with AI Gateway
    • LLM Provider Integration Guides
      • OpenAI
      • Cohere
      • Azure
      • Anthropic
      • Mistral
      • Llama2
      • Vertex/Gemini
      • Amazon Bedrock
    • LLM Library Integration Guides
      • LangChain
    • AI Gateway Analytics
    • Expose and graph AI Metrics
    • AI Gateway Load Balancing
    • AI Gateway plugins
  • Kong Manager
    • Overview
    • Enable Kong Manager
    • Get Started with Kong Manager
      • Services and Routes
      • Rate Limiting
      • Proxy Caching
      • Authentication with Consumers
      • Load Balancing
    • Authentication and Authorization
      • Overview
      • Create a Super Admin
      • Workspaces and Teams
      • Reset Passwords and RBAC Tokens
      • Basic Auth
      • LDAP
        • Configure LDAP
        • LDAP Service Directory Mapping
      • OIDC
        • Configure OIDC
        • OIDC Authenticated Group Mapping
        • Migrate from previous configurations
      • Sessions
      • RBAC
        • Overview
        • Enable RBAC
        • Add a Role and Permissions
        • Create a User
        • Create an Admin
    • Networking Configuration
    • Workspaces
    • Create Consumer Groups
    • Sending Email
    • Troubleshoot
  • Develop Custom Plugins
    • Overview
    • Getting Started
      • Introduction
      • Set up the Plugin Project
      • Add Plugin Testing
      • Add Plugin Configuration
      • Consume External Services
      • Deploy Plugins
    • File Structure
    • Implementing Custom Logic
    • Plugin Configuration
    • Accessing the Data Store
    • Storing Custom Entities
    • Caching Custom Entities
    • Extending the Admin API
    • Writing Tests
    • Installation and Distribution
    • Proxy-Wasm Filters
      • Create a Proxy-Wasm Filter
      • Proxy-Wasm Filter Configuration
    • Plugin Development Kit
      • Overview
      • kong.client
      • kong.client.tls
      • kong.cluster
      • kong.ctx
      • kong.ip
      • kong.jwe
      • kong.log
      • kong.nginx
      • kong.node
      • kong.plugin
      • kong.request
      • kong.response
      • kong.router
      • kong.service
      • kong.service.request
      • kong.service.response
      • kong.table
      • kong.telemetry.log
      • kong.tracing
      • kong.vault
      • kong.websocket.client
      • kong.websocket.upstream
    • Plugins in Other Languages
      • Go
      • Javascript
      • Python
      • Running Plugins in Containers
      • External Plugin Performance
  • Kong Plugins
    • Overview
    • Authentication Reference
    • Allow Multiple Authentication Plugins
    • Plugin Queuing
      • Overview
      • Plugin Queuing Reference
  • Admin API
    • Overview
    • Declarative Configuration
    • Enterprise API
      • Information Routes
      • Health Routes
      • Tags
      • Debug Routes
      • Services
      • Routes
      • Consumers
      • Plugins
      • Certificates
      • CA Certificates
      • SNIs
      • Upstreams
      • Targets
      • Vaults
      • Keys
      • Filter Chains
      • Licenses
      • Workspaces
      • RBAC
      • Admins
      • Consumer Groups
      • Event Hooks
      • Keyring and Data Encryption
      • Audit Logs
      • Status API
    • Open Source API
  • Reference
    • kong.conf
    • Injecting Nginx Directives
    • CLI
    • Key Management
    • The Expressions Language
      • Overview
      • Language References
      • Performance Optimizations
    • Rate Limiting Library
    • WebAssembly
    • Reserved Entity Names
    • FAQ
enterprise-switcher-icon Switch to OSS
On this pageOn this page
  • Prerequisites
  • Step by step
    • Install Pongo
    • Initialize the test environment
    • Manually test plugin
    • Write a test
    • Run the test
  • What’s next?
You are browsing documentation for an older version. See the latest documentation here.

Add Plugin Testing

The following is a guide for setting up a testing environment for Kong Gateway custom plugins.

Prerequisites

This page is the second chapter in the Getting Started guide for developing custom plugins. These instructions refer to the previous chapter in the guide and require the same developer tool prerequisites.

Step by step

Now that you have a basic plugin project, you can build testing automations for it.

Install Pongo

Pongo is a tool that helps you validate and distribute custom plugins for Kong Gateway. Pongo uses Docker to bootstrap a Kong Gateway environment allowing you to quickly load your plugin, run automated testing, and manually validate the plugin’s behavior against various Kong Gateway versions.

The following script can automate the installation of Pongo for you. If you prefer, you can follow the manual installation instructions instead.

If you already have Pongo installed, you can skip to the next step or run the install script to update Pongo to the latest version.

Run the following to install or update Pongo:

curl -Ls https://get.konghq.com/pongo | bash

For the remainder of this guide to work properly, the pongo command must be present in your system path. The script and manual installation instructions above both include hints for putting pongo on your path.

Ensure that the pongo command is available in your PATH by running the command within your project directory:

pongo help

With Pongo installed, you can now set up a test environment for your new plugin.

Initialize the test environment

Pongo lets you validate a plugin’s behavior by giving you tools to quickly run a Kong Gateway with the plugin installed and available.

Let’s validate the plugin manually first, and then you will add automated tests in subsequent steps of this guide.

Note: Kong Gateway runs in a variety of deployment topologies. By default, Pongo runs Kong Gateway in traditional mode, which uses a database to store configured entities such as routes, services, and plugins. Kong Gateway and the database are run in separate containers, letting you cycle the gateway independently of the database. This enables a quick and iterative approach to validating the plugin’s logical behavior while keeping the gateway state independent in the database.

Pongo provides an optional command that initializes the project directory with some default configuration files. You can run it to start a new project.

Important: These commands must be run inside the my-plugin project root directory so that Pongo properly packages and includes the plugin code in the running Kong Gateway.

Initialize the project folder:

pongo init

Now you can start dependency containers for Kong Gateway. By default, this only includes the Postgres database used in traditional mode.

Start the dependencies:

pongo up

Once the dependencies are running successfully, you can run a Kong Gateway container and open a shell within it to interact with the gateway. Pongo runs a Kong Gateway container with various CLI tools pre-installed to help with testing.

Launch the gateway and open a shell with:

pongo shell

Your terminal is now running a shell inside the Kong Gateway container. Your shell prompt should change, showing you the gateway version, the host plugin directory, and current path inside the container. For example, your prompt may look like the following:

[Kong-3.6.1:my-plugin:/kong]$

Pongo provides some aliases to assist with the lifecycle of Kong Gateway and the database. On its first run, you need to initialize the database and start Kong Gateway. Pongo provides the kms alias to perform this common task.

Run the database migrations and start Kong Gateway:

kms

You should see a success message that Kong Gateway has started:

...
64 migrations processed
64 executed
Database is up-to-date

Kong started

As mentioned previously, Pongo installs some development tools to help us test your plugin. You can now validate that the plugin is installed by querying the Admin API using curl and filtering the response with jq:

curl -s localhost:8001 | \
  jq '.plugins.available_on_server."my-plugin"'

You should see a response that matches the information in the plugin’s table:

{
  "priority": 1000,
  "version": "0.0.1"
}

With the test environment initialized, you can now manually run the plugin code.

Manually test plugin

With the plugin installed, you can now configure Kong Gateway entities to invoke and validate the plugin’s behavior.

Note: For each of the following POST requests to the Admin API, you should receive a HTTP/1.1 201 Created response from Kong Gateway indicating the successful creation of the entity.

Still within the Kong Gateway container’s shell, add a new service with the following:

curl -i -s -X POST http://localhost:8001/services \
    --data name=example_service \
    --data url='https://httpbin.konghq.com'

Associate the custom plugin with the example_service service:

curl -is -X POST http://localhost:8001/services/example_service/plugins \
    --data 'name=my-plugin'

Add a new route for sending requests through the example_service:

curl -i -X POST http://localhost:8001/services/example_service/routes \
    --data 'paths[]=/mock' \
    --data name=example_route

The plugin is now configured and will be invoked when Kong Gateway proxies requests via the example_service. Prior to forwarding the response from the upstream, the plugin should append the X-MyPlugin header to the list of response headers.

Test the behavior by proxying a request and asking curl to show the response headers with the -i flag:

curl -i http://localhost:8000/mock/anything

curl should report HTTP/1.1 200 OK and show the response headers from the gateway. You should see X-MyPlugin: response in the set of headers, indicating that the plugin’s logic has been invoked.

For example:

HTTP/1.1 200 OK
Content-Type: application/json
Connection: keep-alive
Content-Length: 529
Access-Control-Allow-Credentials: true
Date: Tue, 12 Mar 2024 14:44:22 GMT
Access-Control-Allow-Origin: *
Server: gunicorn/19.9.0
X-MyPlugin: response
X-Kong-Upstream-Latency: 97
X-Kong-Proxy-Latency: 1
Via: kong/3.6.1
X-Kong-Request-Id: 8ab8c32c4782536592994514b6dadf55

Exit the Kong Gateway shell before proceeding:

exit

For quickly getting started, manually validating a plugin using the Pongo shell works nicely. For production scenarios, you will likely want to deploy automated testing and maybe a test-driven development (TDD) methodology. Let’s see how Pongo can help with this as well.

Write a test

Pongo supports running automated tests using the Busted Lua test framework. In plugin projects, the test files reside under the spec/<plugin-name> directory. For this project, this is the spec/my-plugin folder you created earlier.

The following is a code listing for a test that validates the plugin’s current behavior. Copy this code and place it into a new file located at spec/my-plugin/01-integration_spec.lua. See the code comments for details on the design of the test and the test helpers provided by Kong Gateway.

-- Helper functions provided by Kong Gateway, see https://github.com/Kong/kong/blob/master/spec/helpers.lua
local helpers = require "spec.helpers"

-- matches our plugin name defined in the plugins's schema.lua
local PLUGIN_NAME = "my-plugin"

-- Run the tests for each strategy. Strategies include "postgres" and "off"
--   which represent the deployment topologies for Kong Gateway
for _, strategy in helpers.all_strategies() do

  describe(PLUGIN_NAME .. ": [#" .. strategy .. "]", function()
    -- Will be initialized before_each nested test
    local client

    setup(function()

      -- A BluePrint gives us a helpful database wrapper to
      --    manage Kong Gateway entities directly.
      -- This function also truncates any existing data in an existing db.
      -- The custom plugin name is provided to this function so it mark as loaded
      local blue_print = helpers.get_db_utils(strategy, nil, { PLUGIN_NAME })

      -- Using the BluePrint to create a test route, automatically attaches it
      --    to the default "echo" service that will be created by the test framework
      local test_route = blue_print.routes:insert({
        paths = { "/mock" },
      })

      -- Add the custom plugin to the test route
      blue_print.plugins:insert {
        name = PLUGIN_NAME,
        route = { id = test_route.id },
      }

      -- start kong
      assert(helpers.start_kong({
        -- use the custom test template to create a local mock server
        nginx_conf = "spec/fixtures/custom_nginx.template",
        -- make sure our plugin gets loaded
        plugins = "bundled," .. PLUGIN_NAME,
      }))

    end)

    -- teardown runs after its parent describe block
    teardown(function()
      helpers.stop_kong(nil, true)
    end)

    -- before_each runs before each child describe
    before_each(function()
      client = helpers.proxy_client()
    end)

    -- after_each runs after each child describe
    after_each(function()
      if client then client:close() end
    end)

    -- a nested describe defines an actual test on the plugin behavior
    describe("The response", function()

      it("gets the expected header", function()

        -- invoke a test request
        local r = client:get("/mock/anything", {})

        -- validate that the request succeeded, response status 200
        assert.response(r).has.status(200)

        -- now validate and retrieve the expected response header 
        local header_value = assert.response(r).has.header("X-MyPlugin")

        -- validate the value of that header
        assert.equal("response", header_value)

      end)
    end)
  end)
end

With this test code, Pongo can help automate testing.

Run the test

Pongo can run automated tests with the pongo run command. When this is executed, Pongo determines if dependency containers are already running and will use them if they are. The test library handles truncating existing data in between test runs for us.

Execute a test run:

pongo run

You should see a successful report that looks similar to the following:

[pongo-INFO] auto-starting the test environment, use the 'pongo down' action to stop it
Kong version: 3.6.1

[==========] Running tests from scanned files.
[----------] Global test environment setup.
[----------] Running tests from /kong-plugin/spec/my-plugin/01-integration_spec.lua
[----------] Running tests from /kong-plugin/spec/my-plugin/01-integration_spec.lua
[ RUN      ] /kong-plugin/spec/my-plugin/01-integration_spec.lua:63: my-plugin: [#postgres] The response gets a 'X-MyPlugin' header
[       OK ] /kong-plugin/spec/my-plugin/01-integration_spec.lua:63: my-plugin: [#postgres] The response gets a 'X-MyPlugin' header (6.59 ms)
[ RUN      ] /kong-plugin/spec/my-plugin/01-integration_spec.lua:63: my-plugin: [#off] The response gets a 'X-MyPlugin' header
[       OK ] /kong-plugin/spec/my-plugin/01-integration_spec.lua:63: my-plugin: [#off] The response gets a 'X-MyPlugin' header (4.76 ms)
[----------] 2 tests from /kong-plugin/spec/my-plugin/01-integration_spec.lua (23022.12 ms total)

[----------] Global test environment teardown.
[==========] 2 tests from 1 test file ran. (23022.80 ms total)
[  PASSED  ] 2 tests.

Pongo can also run as part of a Continuous Integration (CI) system. See the repository documentation for more details.

What’s next?

With the project setup and automated testing in place, the next chapter will walk you through adding configurable values to the plugin.


Previous Set Up a Plugin Project
Next Add Plugin Configuration
Thank you for your feedback.
Was this page useful?
Too much on your plate? close cta icon
More features, less infrastructure with Kong Konnect. 1M requests per month for free.
Try it for Free
  • Kong
    Powering the API world

    Increase developer productivity, security, and performance at scale with the unified platform for API management, service mesh, and ingress controller.

    • Products
      • Kong Konnect
      • Kong Gateway Enterprise
      • Kong Gateway
      • Kong Mesh
      • Kong Ingress Controller
      • Kong Insomnia
      • Product Updates
      • Get Started
    • Documentation
      • Kong Konnect Docs
      • Kong Gateway Docs
      • Kong Mesh Docs
      • Kong Insomnia Docs
      • Kong Konnect Plugin Hub
    • Open Source
      • Kong Gateway
      • Kuma
      • Insomnia
      • Kong Community
    • Company
      • About Kong
      • Customers
      • Careers
      • Press
      • Events
      • Contact
  • Terms• Privacy• Trust and Compliance
© Kong Inc. 2025