Add custom plugin testing
Install Pongo, initialize your testing environment, and write test files under the spec/<plugin-name>
directory.
Prerequisites
Series Prerequisites
This page is part of the Get started with custom plugin development series.
Complete the previous page, Set up a custom plugin project before completing this page.
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 that allows 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.
- Run the following to install or update Pongo:
curl -Ls https://get.konghq.com/pongo | bash
- Add Pongo to your path. The result of the previous command should contain instructions on how to do that. For example:
export PATH=$PATH:~/.local/bin
- Ensure that the
pongo
command is available in yourPATH
by running the command within your project directory:pongo help
Initialize the test environment
Pongo lets you validate a plugin’s behavior by giving you tools to quickly run a Kong Gateway instance with the plugin installed and available.
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, Gateway 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
- Start the dependencies, which only include the PostgreSQL in this example:
pongo up
Once the dependencies are running successfully, you can run a Kong Gateway container and open a shell within it. Pongo runs a Kong Gateway container with various CLI tools pre-installed to help with testing.
- Launch Kong Gateway and open a shell:
pongo shell
Your terminal is now running a shell inside the Kong Gateway container. Your shell prompt should change, showing you the Kong Gateway version, the host plugin directory, and current path inside the container. For example, your prompt may look like the following:
[Kong-3.9.0:my-plugin:/kong]$
- Run the database migrations and start Kong Gateway:
kms
You should see a success message saying that Kong Gateway has started.
- Validate that the plugin is installed by querying the Admin API
using
curl
and filtering the response withjq
: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" }
Manually test the plugin
With the plugin installed, we can now configure Kong Gateway entities to invoke and validate the plugin’s behavior.
For each of the following POST
requests to the Admin API, you should receive an 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 Gateway Service:
curl -X POST "http://localhost:8001/services" \ --json '{ "name": "example_service", "url": "https://httpbin.konghq.com" }'
-
Enable the custom plugin on the
example_service
Service:curl -X POST "http://localhost:8001/services/example_service/plugins" \ --json '{ "name": "my-plugin" }'
-
Add a new Route for sending requests through the
example_service
:curl -X POST "http://localhost:8001/services/example_service/routes" \ --json '{ "name": "example_route", "paths": [ "/mock" ] }'
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 theX-MyPlugin
header to the list of response headers. -
Send a request to test the behavior and use the
-i
flag to display the response headers:curl -i "http://localhost:8000/mock/anything"
You should see
X-MyPlugin: response
in the set of headers, indicating that the plugin’s logic has been invoked. -
Exit the Kong Gateway shell before proceeding to the next step:
exit
Write an automated test
For quickly getting started, manually validating a plugin using the Pongo shell works well. 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.
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.
- In your plugin directory, create a test file:
touch spec/my-plugin/01-integration_spec.lua
- Copy and paste this code in the test file:
-- 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
This test validates the plugin’s current behavior. See the code comments for details on the design of the test and the test helpers provided by Kong Gateway.
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.
Execute a test run:
pongo run
You should see a successful report that looks similar to this:
[pongo-INFO] auto-starting the test environment, use the 'pongo down' action to stop it
Kong version: 3.9.0
[==========] Running tests from scanned files.
[----------] Global test environment setup.
[----------] 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 the expected header
[ OK ] /kong-plugin/spec/my-plugin/01-integration_spec.lua:63: my-plugin: [#postgres] The response gets the expected header (12.56 ms)
[ RUN ] /kong-plugin/spec/my-plugin/01-integration_spec.lua:63: my-plugin: [#off] The response gets the expected header
[ OK ] /kong-plugin/spec/my-plugin/01-integration_spec.lua:63: my-plugin: [#off] The response gets the expected header (11.42 ms)
[----------] 2 tests from /kong-plugin/spec/my-plugin/01-integration_spec.lua (48425.41 ms total)
[----------] Global test environment teardown.
[==========] 2 tests from 1 test file ran. (48436.36 ms total)
[ PASSED ] 2 tests.
Pongo can also run as part of a Continuous Integration (CI) system. See the repository documentation for more details.