apisix-dev
APISIX Development Environment Setup
This skill guides you through setting up the APISIX testing environment and running tests using TEST::NGINX.
Environment Requirements
Ubuntu Only
IMPORTANT: Direct test execution is only supported on Ubuntu.
Before proceeding, check the operating system:
uname -a && cat /etc/os-release 2>/dev/null | head -5
If NOT Ubuntu:
-
Option A: Use Ubuntu Environment
- Start an Ubuntu VM, container, or WSL2
- Run commands there and paste error logs back for analysis
-
Option B: Use DevContainers (VSCode)
- See: https://apisix.apache.org/docs/apisix/build-apisix-dev-environment-devcontainers/
- Setup steps:
git clone https://github.com/apache/apisix.git cd apisix code . # In VSCode: Cmd/Ctrl+Shift+P -> "Dev Containers: Reopen in Container" - Warning: Some tests may not run normally in DevContainer due to container limitations
If Ubuntu: Proceed with the setup below.
Quick Start (Ubuntu)
Step 1: Clone Repository with Submodules
git clone --recurse-submodules https://github.com/apache/apisix.git
cd apisix
If already cloned without submodules:
git submodule update --init --recursive
Step 2: Install Dependencies Using CI Scripts
APISIX provides CI scripts that handle all dependency installation. Use these scripts to ensure consistency with the official CI environment.
Reference the CI workflow: https://github.com/apache/apisix/blob/master/.github/workflows/build.yml
Key CI Scripts:
ci/common.sh- Common utilities and dependency functionsci/linux_openresty_runner.sh- Main runner scriptci/linux_openresty_common_runner.sh- Installation functions (before_install,do_install)
Run the installation:
# Source the CI scripts and run installation
cd apisix
# Set required environment variables
export OPENRESTY_VERSION=default
export SERVER_NAME=linux_openresty
# Source and run the CI installation functions
. ./ci/common.sh
. ./ci/linux_openresty_common_runner.sh
# Run before_install (installs system dependencies, Test::Nginx)
before_install
# Run do_install (installs OpenResty, Lua deps, test-nginx, etc.)
do_install
What the CI scripts install:
- System packages (cpanminus, build-essential, libssl-dev, etc.)
- Test::Nginx via cpanm
- OpenResty with correct version
- Lua dependencies (
make deps) - test-nginx from openresty/test-nginx
- Additional tools (grpcurl, Node.js, etc.)
Note: etcd runs in Docker container, not installed locally.
Step 3: Verify Installation
# Verify OpenResty
openresty -v
# Verify test-nginx exists
ls test-nginx/
Note: If you encounter issues with the CI scripts, check the latest build.yml for any changes to the installation process. The CI scripts are the source of truth for the test environment setup.
Environment Variables
Set these environment variables before running tests:
export OPENRESTY_PREFIX="/usr/local/openresty"
export PATH=$OPENRESTY_PREFIX/nginx/sbin:$OPENRESTY_PREFIX/luajit/bin:$OPENRESTY_PREFIX/bin:$PATH
# Optional - adjust based on your setup
export OPENRESTY_VERSION=default
export SERVER_NAME=linux_openresty
Verify the setup:
which openresty
openresty -v
which etcd
etcd --version
Running Tests
Basic Test Execution
Tests use the prove command with TEST::NGINX. Run from the APISIX repository root:
# Run a single test file
FLUSH_ETCD=1 prove -I./test-nginx/lib -I./ t/path/to/test.t
# Example: Run a specific test
FLUSH_ETCD=1 prove -I./test-nginx/lib -I./ t/plugin/limit-count.t
Test Command Options
| Option | Description |
|---|---|
FLUSH_ETCD=1 |
Flush etcd before running tests (recommended) |
-I./test-nginx/lib |
Include test-nginx library path |
-I./ |
Include current directory |
-v |
Verbose output |
-r |
Recurse into directories |
Run Multiple Tests
# Run all tests in a directory
FLUSH_ETCD=1 prove -I./test-nginx/lib -I./ -r t/plugin/
# Run tests matching a pattern
FLUSH_ETCD=1 prove -I./test-nginx/lib -I./ t/plugin/limit-*.t
Start Required Services
Before running tests, start the CI environment using Docker:
# Start all required services (etcd, etc.) via Docker
make ci-env-up project_compose_ci=ci/pod/docker-compose.common.yml
This starts the necessary containers including etcd. No manual etcd installation is required.
To stop the services:
make ci-env-down
Lint Before Committing
IMPORTANT: Always lint test files before committing.
# Lint all code (source + tests)
make lint
# Or run individual lint scripts
./utils/check-lua-code-style.sh # Lint source code
./utils/check-test-code-style.sh # Lint test files
The make lint target:
- Requires
utilstarget (downloads linting utilities) - Runs
check-lua-code-style.shfor source code - Runs
check-test-code-style.shfor test files
Reference: https://github.com/apache/apisix/blob/master/Makefile#L171-L178
Skippable Steps (Initial Setup)
For initial testing, you can skip these steps from the CI workflow:
- WASM-related steps - Only needed for WASM plugin tests
- Start some services - Only needed for specific integration tests
- Build XDS Library - Only needed for xDS-related tests
- Build WASM Core - Only needed for WASM tests
- Dubbo backend - Only needed for Dubbo plugin tests
APISIX Deployment Modes
Reference: https://apisix.apache.org/docs/apisix/deployment-modes/
APISIX supports three deployment modes:
| Mode | Description | Config Provider |
|---|---|---|
traditional |
Data plane + control plane together | etcd only |
decoupled |
Separate data/control planes | etcd only |
standalone |
Data plane with local file config | yaml or json |
Using YAML Config Provider
CRITICAL: Only data_plane role supports config_provider: yaml.
CORRECT configuration (in conf/config.yaml):
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
INCORRECT - This does NOT work:
# DO NOT USE - traditional role does not support yaml config provider
deployment:
role: traditional
role_traditional:
config_provider: yaml
Symptoms of incorrect configuration:
config.yamlgets overwritten when runningapisix start/reload/init- Content configured in
apisix.yamlhas no effect
YAML Configuration File
When using config_provider: yaml:
- Rules are stored in
conf/apisix.yaml - File must end with
#ENDmarker for APISIX to load it - APISIX checks for changes every second and hot-reloads
Example conf/apisix.yaml:
routes:
- uri: /hello
upstream:
nodes:
'127.0.0.1:8080': 1
type: roundrobin
#END
CI Reference
IMPORTANT: Always check the official CI workflow for the latest installation process. The CI scripts are maintained by the APISIX team and are the source of truth.
Official CI workflow: https://github.com/apache/apisix/blob/master/.github/workflows/build.yml
Key CI scripts in the repository:
| Script | Purpose |
|---|---|
ci/common.sh |
Common utilities, dependency functions, tool installation |
ci/linux_openresty_runner.sh |
Main Linux runner (sources common_runner) |
ci/linux_openresty_common_runner.sh |
before_install(), do_install(), script() functions |
CI Functions:
before_install()- Installs system dependencies, Test::Nginxdo_install()- Installs OpenResty, etcd, Lua deps, test-nginx, grpcurl, etc.script()- Runs the actual test suite
When something doesn't work: Check if the CI scripts have been updated. The build.yml and CI scripts evolve with the project.
Troubleshooting
Test Fails with "nginx: command not found"
Ensure OpenResty is in PATH:
export PATH=/usr/local/openresty/nginx/sbin:$PATH
which nginx
etcd Connection Failed
Ensure the CI environment is running:
# Start CI services (includes etcd)
make ci-env-up project_compose_ci=ci/pod/docker-compose.common.yml
# Check if containers are running
docker ps | grep etcd
Permission Denied Errors
Some tests require sudo:
sudo -E FLUSH_ETCD=1 prove -I./test-nginx/lib -I./ t/path/to/test.t
Missing Lua Dependencies
Reinstall dependencies:
make deps
Submodule Issues
Re-initialize submodules:
git submodule update --init --recursive
TEST::NGINX Basics
APISIX tests are written using TEST::NGINX, a Perl-based testing framework.
Reference Existing Tests First
IMPORTANT: When writing new tests, always reference similar existing tests in the APISIX repository first.
Test directory: https://github.com/apache/apisix/tree/master/t
| Directory | Test Type |
|---|---|
t/plugin/ |
Plugin tests (limit-count, key-auth, cors, etc.) |
t/admin/ |
Admin API tests |
t/core/ |
Core functionality tests |
t/node/ |
Node/upstream tests |
t/router/ |
Router tests |
t/stream/ |
Stream proxy tests |
t/discovery/ |
Service discovery tests |
t/xrpc/ |
xRPC protocol tests |
How to find similar tests:
# Search for tests related to a plugin
ls t/plugin/ | grep -i <keyword>
# Search for specific patterns in test files
grep -r "your_pattern" t/
# Example: Find tests using key-auth
grep -r "key-auth" t/plugin/
Why reference existing tests:
- Follow established patterns and conventions
- Understand how to set up test fixtures
- Learn correct assertion methods
- Avoid reinventing test utilities
Test File Structure
use t::APISIX 'no_plan';
repeat_each(1);
no_long_string();
no_root_location();
run_tests;
__DATA__
=== TEST 1: test description
--- config
location /t {
content_by_lua_block {
-- test code here
}
}
--- request
GET /t
--- response_body
expected response
--- no_error_log
[error]
Common Test Sections
| Section | Description |
|---|---|
--- config |
Nginx configuration |
--- request |
HTTP request to send |
--- response_body |
Expected response body |
--- error_code |
Expected HTTP status code |
--- no_error_log |
Patterns that should NOT appear in error log |
--- error_log |
Patterns that SHOULD appear in error log |
Non-Ubuntu Environment Workflow
If you're not on Ubuntu:
- Start Ubuntu environment (VM, container, WSL2)
- Run commands there
- If errors occur: Copy the complete error log
- Paste to AI for analysis: The AI can help diagnose issues without direct execution
Example error sharing format:
Command: FLUSH_ETCD=1 prove -I./test-nginx/lib -I./ t/plugin/limit-count.t
Error:
[paste complete error output here]