Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request buffering tests #1

Merged
merged 5 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ RUN apt-get install -y \
unzip \
git \
m4 \
libyaml-dev
libyaml-dev \
libcurl4-openssl-dev

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need to introduce a dependence for the release if it's only used in tests.
I'm not familiar with the build process and this looks like a part of it to me.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks for the review!
This Dockerfile is not used for releases though! It is the .devcontainer/Dockerfile. It's used for development: https://code.visualstudio.com/docs/devcontainers/containers
For me it was the only way I could get the kong stack running locally to run the integration tests on my own PC.

So it's not part of the kong build process.

2 changes: 2 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ services:
KONG_PG_HOST: db
OPENSSL_DIR: /usr/local/kong
CRYPTO_DIR: /usr/local/kong
# env vars to be able to run tests
KONG_TEST_PG_DATABASE: kong
Comment on lines +38 to +39

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

~Same comment, this is part of VSCode's .devcontainer setup.
I think running tests is part of development.


# Overrides default command so things don't shut down after the process ends.
command: /bin/sh -c "while sleep 1000; do :; done"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:

- name: Install packages
if: steps.cache-deps.outputs.cache-hit != 'true'
run: sudo apt update && sudo apt install libyaml-dev valgrind libprotobuf-dev
run: sudo apt update && sudo apt install libyaml-dev valgrind libprotobuf-dev libcurl4-openssl-dev

- name: Build Kong
if: steps.cache-deps.outputs.cache-hit != 'true'
Expand Down
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ $(info starting make in kong)
OS := $(shell uname | awk '{print tolower($$0)}')
MACHINE := $(shell uname -m)

DEV_ROCKS = "busted 2.1.1" "busted-htest 1.0.0" "luacheck 1.1.0" "lua-llthreads2 0.1.6" "http 0.4" "ldoc 1.4.6"
DEV_ROCKS = "busted 2.1.1" "busted-htest 1.0.0" "luacheck 1.1.0" "lua-llthreads2 0.1.6" "http 0.4" "ldoc 1.4.6" "Lua-cURL 0.3.13"
WIN_SCRIPTS = "bin/busted" "bin/kong" "bin/kong-health"
BUSTED_ARGS ?= -v
TEST_CMD ?= bin/busted $(BUSTED_ARGS)
Expand All @@ -12,10 +12,12 @@ ifeq ($(OS), darwin)
OPENSSL_DIR ?= $(shell brew --prefix)/opt/openssl
GRPCURL_OS ?= osx
YAML_DIR ?= $(shell brew --prefix)/opt/libyaml
CURL_INCDIR ?= /usr/include/x86_64-linux-gnu/
else
OPENSSL_DIR ?= /usr
GRPCURL_OS ?= $(OS)
YAML_DIR ?= /usr
CURL_INCDIR ?= /usr/include/x86_64-linux-gnu/
endif

ifeq ($(MACHINE), aarch64)
Expand Down Expand Up @@ -164,7 +166,7 @@ dependencies: bin/grpcurl
echo $$rock already installed, skipping ; \
else \
echo $$rock not found, installing via luarocks... ; \
luarocks install $$rock OPENSSL_DIR=$(OPENSSL_DIR) CRYPTO_DIR=$(OPENSSL_DIR) || exit 1; \
luarocks install $$rock OPENSSL_DIR=$(OPENSSL_DIR) CRYPTO_DIR=$(OPENSSL_DIR) CURL_INCDIR=$(CURL_INCDIR) || exit 1; \
fi \
done;

Expand Down
315 changes: 196 additions & 119 deletions spec/02-integration/05-proxy/27-unbuffered_spec.lua
Original file line number Diff line number Diff line change
@@ -1,25 +1,53 @@
local helpers = require "spec.helpers"
local random = require "resty.random"
local rstring = require "resty.string"
local curl = require("cURL")

local HTTP_VERSIONS = {
CURL_HTTP_VERSION_NONE = 0,
CURL_HTTP_VERSION_1_0 = 1,
CURL_HTTP_VERSION_1_1 = 2,
CURL_HTTP_VERSION_2_0 = 3,
CURL_HTTP_VERSION_2TLS = 4,
CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE = 5
}

local function curl_post(url, body, http_version)
http_version = http_version or HTTP_VERSIONS["CURL_HTTP_VERSION_2_0"]

local c = curl.easy{
url = url,
ssl_verifypeer = false,
ssl_verifyhost = false,
post = true,
postfields = body,
--[curl.OPT_VERBOSE] = true,
[curl.OPT_HEADER] = true,
[curl.OPT_HTTP_VERSION] = http_version,
}
local response = {}
c:setopt_writefunction(table.insert, response)
c:perform()

local status = c:getinfo_response_code()
local full_response = table.concat(response)
local raw_headers = string.sub(full_response, 1, c:getinfo(curl.INFO_HEADER_SIZE))
local return_body = string.sub(full_response, c:getinfo(curl.INFO_HEADER_SIZE))

--parse headers
local return_headers = {}
for header in string.gmatch(raw_headers, "[%w%-]+:[^\n]+") do
local index = string.find(header, ":")
return_headers[string.lower(string.sub(header, 1, index-1))] = string.sub(header, index+2)
end

return status, return_headers, return_body
end

-- HTTP 1.1 Chunked Body (5 MB)
local function body()
local chunk = "2000" .."\r\n" .. rstring.to_hex(random.bytes(4096)) .. "\r\n"
local i = 0
return function()
i = i + 1

if i == 641 then
return "0\r\n\r\n"
end

if i == 642 then
return nil
end

return chunk
end
--- HTTP Body (5 MB)
local function body()
return rstring.to_hex(random.bytes(5*1024*1024/2))
end


Expand Down Expand Up @@ -89,109 +117,6 @@ for _, strategy in helpers.each_strategy() do
proxy_client:close()
end)

describe("request latency", function()
local buffered_latency
local unbuffered_latency
local unbuffered_request_latency
local unbuffered_response_latency

it("is calculated for buffered", function()
warmup_client:post("/buffered/post", { body = "warmup" })

local res = proxy_client:send({
method = "POST",
path = "/buffered/post",
body = body(),
headers = {
["Transfer-Encoding"] = "chunked",
["Content-Type"] = "application/octet-stream",
}
})

assert.equal(200, res.status)

buffered_latency = tonumber(res.headers["X-Kong-Proxy-Latency"])

assert.is_number(buffered_latency)
end)

it("is calculated for unbuffered", function()
warmup_client:post("/unbuffered/post", { body = "warmup" })

local res = proxy_client:send({
method = "POST",
path = "/unbuffered/post",
body = body(),
headers = {
["Transfer-Encoding"] = "chunked",
["Content-Type"] = "application/octet-stream",
}
})

assert.equal(200, res.status)

unbuffered_latency = tonumber(res.headers["X-Kong-Proxy-Latency"])

assert.is_number(unbuffered_latency)
end)

it("is calculated for unbuffered request", function()
warmup_client:post("/unbuffered-request/post", { body = "warmup" })

local res = proxy_client:send({
method = "POST",
path = "/unbuffered-request/post",
body = body(),
headers = {
["Transfer-Encoding"] = "chunked",
["Content-Type"] = "application/octet-stream",
}
})

assert.equal(200, res.status)

unbuffered_request_latency = tonumber(res.headers["X-Kong-Proxy-Latency"])

assert.is_number(unbuffered_request_latency)
end)

it("is calculated for unbuffered response", function()
warmup_client:post("/unbuffered-response/post", { body = "warmup" })

local res = proxy_client:send({
method = "POST",
path = "/unbuffered-response/post",
body = body(),
headers = {
["Transfer-Encoding"] = "chunked",
["Content-Type"] = "application/octet-stream",
}
})

assert.equal(200, res.status)

unbuffered_response_latency = tonumber(res.headers["X-Kong-Proxy-Latency"])

assert.is_number(unbuffered_response_latency)
end)

it("is greater for buffered than unbuffered", function()
assert.equal(true, buffered_latency > unbuffered_latency)
end)

it("is greater for buffered than unbuffered request", function()
assert.equal(true, buffered_latency > unbuffered_request_latency)
end)

it("is greater for unbuffered response than unbuffered", function()
assert.equal(true, unbuffered_response_latency > unbuffered_latency)
end)

it("is greater for unbuffered response than unbuffered request", function()
assert.equal(true, unbuffered_response_latency > unbuffered_request_latency)
end)
end)

describe("number of response chunks", function()
local buffered_chunks = 0
local unbuffered_chunks = 0
Expand Down Expand Up @@ -296,3 +221,155 @@ for _, strategy in helpers.each_strategy() do
end)
end)
end


-- Tests for HTTP/1.1 and HTTP/2.0
local versions_to_test = {"CURL_HTTP_VERSION_1_1", "CURL_HTTP_VERSION_2_0"}
for _, version in pairs(versions_to_test) do
local http_version = HTTP_VERSIONS[version]

for _, strategy in helpers.each_strategy() do
describe("HTTP 2.0 Buffered requests/response [#" .. strategy .. "] [#"..version.."]", function()
local warmup_client
local base_url
local proxy_ip
local proxy_port

lazy_setup(function()
local bp = helpers.get_db_utils(strategy, {
"routes",
"services"
})

local service = bp.services:insert()

bp.routes:insert({
protocols = { "http", "https" },
paths = { "/buffered" },
request_buffering = true,
response_buffering = true,
service = service,
})

bp.routes:insert({
protocols = { "http", "https" },
paths = { "/unbuffered" },
request_buffering = false,
response_buffering = false,
service = service,
})

bp.routes:insert({
protocols = { "http", "https" },
paths = { "/unbuffered-request" },
request_buffering = false,
response_buffering = true,
service = service,
})

bp.routes:insert({
protocols = { "http", "https" },
paths = { "/unbuffered-response" },
request_buffering = true,
response_buffering = false,
service = service,
})

assert(helpers.start_kong {
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
})

end)

lazy_teardown(function()
warmup_client:close()
helpers.stop_kong()
end)

before_each(function()
proxy_ip = helpers.get_proxy_ip(true, true)
proxy_port = helpers.get_proxy_port(true, true)
warmup_client = helpers.proxy_client()
base_url = "https://" .. proxy_ip .. ":" .. proxy_port
end)

describe("request latency", function()
local buffered_latency
local unbuffered_latency
local unbuffered_request_latency
local unbuffered_response_latency
local status, headers, _


it("is calculated for buffered", function()
warmup_client:post("/buffered/post", { body = "warmup" })

status, headers, _ = curl_post(
base_url .. "/buffered/post", body(),
http_version
)
assert.equal(200, status)

buffered_latency = tonumber(headers["x-kong-proxy-latency"])
assert.is_number(buffered_latency)

end)

it("is calculated for unbuffered", function()
warmup_client:post("/unbuffered/post", { body = "warmup" })

status, headers, _ = curl_post(
base_url .. "/unbuffered/post", body(),
http_version
)
assert.equal(200, status)
unbuffered_latency = tonumber(headers["x-kong-proxy-latency"])
assert.is_number(unbuffered_latency)

end)

it("is calculated for unbuffered request", function()
warmup_client:post("/unbuffered-request/post", { body = "warmup" })

status, headers, _ = curl_post(
base_url .. "/unbuffered-request/post", body(),
http_version
)
assert.equal(200, status)
unbuffered_request_latency = tonumber(headers["x-kong-proxy-latency"])
assert.is_number(unbuffered_request_latency)

end)

it("is calculated for unbuffered response", function()
warmup_client:post("/unbuffered-response/post", { body = "warmup" })

status, headers, _ = curl_post(
base_url .. "/unbuffered-response/post", body(),
http_version
)
assert.equal(200, status)
unbuffered_response_latency = tonumber(headers["x-kong-proxy-latency"])
assert.is_number(unbuffered_response_latency)
end)

it("is greater for buffered than unbuffered", function()
assert.equal(true, buffered_latency > unbuffered_latency)
end)

it("is greater for buffered than unbuffered request", function()
assert.equal(true, buffered_latency > unbuffered_request_latency)
end)

it("is greater for unbuffered response than unbuffered", function()
assert.equal(true, unbuffered_response_latency > unbuffered_latency)
end)

it("is greater for unbuffered response than unbuffered request", function()
assert.equal(true, unbuffered_response_latency > unbuffered_request_latency)
end)
end)
end)
end
end