We used pytest to test the project as we developed features, both running locally and on the GitHub Actions platform.
To test our webserver, we followed these steps:
- Create a virtual environment for our Python tester
- Set up fixtures that start and stop our server with different configurations
- Write integration tests that validate server responses
Our test fixtures use subprocess to launch the server with different configuration files:
@pytest.fixture(scope="function")
def webserver_normal_config():
server = start_webserver("tests/config/default.conf")
yield
server.terminate()Tests then use these fixtures to verify different aspects of the server functionality:
def test_normal_config_upload(webserver_normal_config):
"""Test file upload (only works with normal config)"""
test_file = 'tests/uploadtest.txt'
upload_url = 'http://localhost:4244/upload/test.txt'
# Test implementation...For debugging, netcat (nc) and curl are very useful command-line tools.
HTTP headers always end with the sequence \r\n\r\n. This marks the end of the headers and the beginning of the body, if present. Typically, GET requests don't have a body. In POST requests, the Content-Length header specifies the length of the body.
You can connect to your server's port using netcat:
nc localhost 4243However, to properly send HTTP headers with the CRLF sequence, it's easier to pipe a request to netcat:
echo -e "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n" | nc localhost 4243The -e option enables interpretation of backslash escapes, necessary for the \r and \n characters. You can also use -n with echo to avoid an extra newline at the end of the string.
Test a malformed request:
echo -e "\r\n\r\na" | nc localhost 4243Test a POST request:
echo -e "POST / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 3\r\n\r\na=1" | nc localhost 4243To set up CI/CD with GitHub workflows:
- Create a folder:
.github/workflows - Create a file:
ci.ymlwith the following content:
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: true
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install pytest
- name: Build
run: make
- name: Run tests
run: |
make venv
make testAfter pushing this workflow to your repository, go to the Actions tab in GitHub to see it running.
On macOS, the VS Code debugger uses LLDB. To configure it:
- Create a
.vscode/launch.jsonfile - Set up a configuration for C++ debugging with LLDB
For Linux, you'd typically use GDB as the backend for debugging in VS Code.
Here are several examples of using curl to test various HTTP functionality. Run your webserver on localhost:4244 before trying these commands. The -v flag provides verbose output, showing both request and response headers.
Create a test file:
echo -e "This is the content of the file.\nSecond line." > report.txt Send a multipart POST request:
curl -v -X POST \
-F "text_field=Simple text value" \
-F "file_upload=@report.txt;type=text/plain" \
http://localhost:4244/cgi/hello.pyClean up:
rm report.txtKey parameters explained:
-X POST: Specifies the POST method (though-Fimplies POST)-F "field=value": Sends a simple form field-F "name=@filename;type=mimetype": Uploads a file with the specified MIME type- curl automatically generates the appropriate
Content-Typeheader with boundary
# Pipe data to curl using echo
echo -n -e "This is the first chunk.\nAnd this is the second chunk.\nFinally, the third chunk." | \
curl -v -X POST \
-H "Content-Type: text/plain" \
-H "Transfer-Encoding: chunked" \
--data-binary @- \
http://localhost:4244/cgi/hello.pyKey parameters explained:
-X POST: Specifies the POST method-H: Sets specific headers for the request--data-binary @-: Reads data from standard input and sends it binary-exact- The combination with
Transfer-Encoding: chunkedmakes curl format the data in chunks
curl -v -X DELETE http://localhost:4244/cgi/hello.py/resource/to/deleteKey parameters explained:
-X DELETE: Specifies the DELETE HTTP method- The path info
/resource/to/deleteis part of the URL that can be processed by the server