This is an automated email from the ASF dual-hosted git repository.
spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new a671909 test: fuzz with the simple http case (#4815)
a671909 is described below
commit a671909576ae98f697df8f225124c0b09989cdb6
Author: 罗泽轩 <[email protected]>
AuthorDate: Tue Aug 17 11:58:30 2021 +0800
test: fuzz with the simple http case (#4815)
---
.github/workflows/fuzzing-ci.yaml | 3 +-
t/fuzzing/public.py | 16 +++--
t/fuzzing/simple_http.py | 121 ++++++++++++++++++++++++++++++++++++++
3 files changed, 134 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/fuzzing-ci.yaml
b/.github/workflows/fuzzing-ci.yaml
index 282eacd..71eaf8b 100644
--- a/.github/workflows/fuzzing-ci.yaml
+++ b/.github/workflows/fuzzing-ci.yaml
@@ -79,6 +79,7 @@ jobs:
run: |
python $PWD/t/fuzzing/vars_route_test.py
- - name: run client abort test
+ - name: run check leak test
run: |
python $PWD/t/fuzzing/client_abort.py
+ python $PWD/t/fuzzing/simple_http.py
diff --git a/t/fuzzing/public.py b/t/fuzzing/public.py
index 4d67baf..500b3d3 100644
--- a/t/fuzzing/public.py
+++ b/t/fuzzing/public.py
@@ -88,29 +88,35 @@ def gc():
conn.request("POST", "/v1/gc")
conn.close()
+def leak_count():
+ return int(os.environ.get("APISIX_FUZZING_LEAK_COUNT") or 100)
+
+LEAK_COUNT = leak_count()
+
def check_leak(f):
@wraps(f)
def wrapper(*args, **kwds):
- leak_count = 100
+ global LEAK_COUNT
samples = []
- for i in range(leak_count):
+ for i in range(LEAK_COUNT):
f(*args, **kwds)
gc()
samples.append(sum_memory())
count = 0
- for i in range(1, leak_count):
+ for i in range(1, LEAK_COUNT):
if samples[i - 1] < samples[i]:
count += 1
print(samples)
sloped = get_linear_regression_sloped(samples)
print(sloped)
- print(count / leak_count)
+ print(count / LEAK_COUNT)
if os.environ.get("CI"): # CI is not stable
return
- if sloped > 1000 and (count / leak_count) > 0.1:
+ # the threshold is chosen so that we can find leaking a table per
request
+ if sloped > 10000 and (count / LEAK_COUNT) > 0.2:
raise AssertionError("memory leak")
return wrapper
diff --git a/t/fuzzing/simple_http.py b/t/fuzzing/simple_http.py
new file mode 100755
index 0000000..f2d2099
--- /dev/null
+++ b/t/fuzzing/simple_http.py
@@ -0,0 +1,121 @@
+#! /usr/bin/env python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This file provides a fuzzing test with most common plugins via plain HTTP
request
+import http.client
+import json
+import random
+import threading
+from public import check_leak, LEAK_COUNT, run_test
+
+
+REQ_PER_THREAD = 50
+THREADS_NUM = 10
+TOTOL_ROUTES = 50
+
+
+def create_route():
+ conf = json.dumps({
+ "username": "jack",
+ "plugins": {
+ "jwt-auth": {
+ "key": "user-key",
+ "secret": "my-secret-key"
+ }
+ }
+ })
+ conn = http.client.HTTPConnection("127.0.0.1", port=9080)
+ conn.request("PUT", "/apisix/admin/consumers", conf,
+ headers={
+ "X-API-KEY":"edd1c9f034335f136f87ad84b625c8f1",
+ })
+ response = conn.getresponse()
+ assert response.status <= 300, response.read()
+
+ for i in range(TOTOL_ROUTES):
+ conn = http.client.HTTPConnection("127.0.0.1", port=9080)
+ i = str(i)
+ conf = json.dumps({
+ "uri": "/*",
+ "host": "test" + i + ".com",
+ "plugins": {
+ "limit-count": {
+ "count": LEAK_COUNT * REQ_PER_THREAD * THREADS_NUM,
+ "time_window": 3600,
+ },
+ "jwt-auth": {
+ },
+ "proxy-rewrite": {
+ "uri": "/" + i,
+ "headers": {
+ "X-APISIX-Route": "apisix-" + i
+ }
+ },
+ "response-rewrite": {
+ "headers": {
+ "X-APISIX-Route": "$http_x_apisix_route"
+ }
+ },
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:6666": 1
+ },
+ "type": "roundrobin"
+ },
+ })
+
+ conn.request("PUT", "/apisix/admin/routes/" + i, conf,
+ headers={
+ "X-API-KEY":"edd1c9f034335f136f87ad84b625c8f1",
+ })
+ response = conn.getresponse()
+ assert response.status <= 300, response.read()
+
+def req():
+ jwt_token = ("Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."+
+ "eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTg3OTMxODU0MX0."+
+ "fNtFJnNmJgzbiYmGB0Yjvm-l6A6M4jRV1l4mnVFSYjs")
+ route_id = str(random.randrange(TOTOL_ROUTES))
+ conn = http.client.HTTPConnection("127.0.0.1", port=9080)
+ conn.request("GET", "/",
+ headers={
+ "Host":"test" + route_id + ".com",
+ "Authorization":jwt_token,
+ })
+ response = conn.getresponse()
+ assert response.status == 200, response.read()
+ hdr = response.headers["X-APISIX-Route"]
+ assert hdr == "apisix-" + route_id, hdr
+
+def run_in_thread():
+ for i in range(REQ_PER_THREAD):
+ req()
+
+@check_leak
+def run():
+ th = [threading.Thread(target=run_in_thread) for i in range(THREADS_NUM)]
+ for t in th:
+ t.start()
+ for t in th:
+ t.join()
+
+
+if __name__ == "__main__":
+ run_test(create_route, run)