From a322197d75d6cf0e43a179205791d59511a36df7 Mon Sep 17 00:00:00 2001 From: kthui <18255193+kthui@users.noreply.github.com> Date: Tue, 6 Jun 2023 16:38:23 -0700 Subject: [PATCH] Add test for detecting S3 http2 upgrade request --- qa/L0_storage_S3_local/mock_s3_service.py | 107 ++++++++++++++++++++++ qa/L0_storage_S3_local/test.sh | 29 +++++- 2 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 qa/L0_storage_S3_local/mock_s3_service.py diff --git a/qa/L0_storage_S3_local/mock_s3_service.py b/qa/L0_storage_S3_local/mock_s3_service.py new file mode 100644 index 00000000000..61a6152b98e --- /dev/null +++ b/qa/L0_storage_S3_local/mock_s3_service.py @@ -0,0 +1,107 @@ +# Copyright 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of NVIDIA CORPORATION nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import time +import threading +from http.server import HTTPServer, BaseHTTPRequestHandler + + +class MockS3Service(): + + __address = "localhost" + __port = 8080 + + def __init__(self): + # Test passed when: + # - one or more requests are received; and + # - all requests do not advertise for HTTP/2. + test_results = [0, False] # [requests received, advertised for HTTP/2] + + class RequestValidator(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + + def __CheckRequest(self): + # Requests received + test_results[0] += 1 + # Advertised for HTTP/2 + if "connection" in self.headers: + v = self.headers["connection"] + if "upgrade" in v or "http2" in v: + test_results[1] = True + if "upgrade" in self.headers and "h2c" in self.headers[ + "upgrade"]: + test_results[1] = True + if "http2-settings" in self.headers: + test_results[1] = True + + def do_HEAD(self): + self.__CheckRequest() + self.send_response(200) + self.end_headers() + + def do_GET(self): + self.__CheckRequest() + self.send_error(404, "Thank you for using the mock s3 service!", + "Your bucket is not found here!") + + self.__test_results = test_results + self.__server = HTTPServer((self.__address, self.__port), + RequestValidator) + self.__service_thread = threading.Thread( + target=self.__server.serve_forever) + + def __enter__(self): + self.__service_thread.start() + + def __exit__(self, exc_type, exc_val, exc_tb): + self.__server.shutdown() + self.__server.server_close() + self.__service_thread.join() + + def TestPassed(self): + # [requests received, advertised for HTTP/2] + return self.__test_results[0] > 0 and not self.__test_results[1] + + +if __name__ == "__main__": + + # Initialize mock service + mock_s3_service = MockS3Service() + + # Start service and poll until test passed or timed-out + with mock_s3_service: + poll_interval = 1 # seconds + timeout = 10 # seconds + elapsed_time = 0 # seconds + while not mock_s3_service.TestPassed() and elapsed_time < timeout: + elapsed_time += poll_interval + time.sleep(poll_interval) + + # Print the result + if mock_s3_service.TestPassed(): + print("TEST PASSED") + else: + print("TEST FAILED") diff --git a/qa/L0_storage_S3_local/test.sh b/qa/L0_storage_S3_local/test.sh index 27d5e67daa7..7f07fbd24b8 100755 --- a/qa/L0_storage_S3_local/test.sh +++ b/qa/L0_storage_S3_local/test.sh @@ -355,10 +355,33 @@ done kill $MINIO_PID wait $MINIO_PID -if [ $RET -eq 0 ]; then - echo -e "\n***\n*** Test Passed\n***" +# Test the S3 client will not advertise HTTP/2 +TEST_LOG="./http2_advertise_test.log" +python3 mock_s3_service.py > $TEST_LOG 2>&1 & +sleep 2 # make sure the mock service has started +SERVER_LOG="./http2_advertise_test.server.log" +SERVER_ARGS="--model-repository=s3://localhost:8080/dummy-bucket --exit-timeout-secs=120" +run_server +if [ "$SERVER_PID" != "0" ]; then + echo -e "\n***\n*** Unexpected server start $SERVER\n***" + cat $SERVER_LOG + kill $SERVER_PID + wait $SERVER_PID + RET=1 else - echo -e "\n***\n*** Test Failed\n***" + sleep 2 # make sure the mock service has stopped + PASSED_MSG="TEST PASSED" + if ! grep "$PASSED_MSG" $TEST_LOG; then + echo -e "\n***\n*** S3 client HTTP/2 advertise test failed\n***" + cat $TEST_LOG + RET=1 + fi fi +# Print and return test result +if [ $RET -eq 0 ]; then + echo -e "\n***\n*** Test Passed\n***" +else + echo -e "\n***\n*** Test Failed\n***" +fi exit $RET