Skip to content

Commit dacf155

Browse files
httpx HTTP/2 Testing (#1245)
* Add nginx runner for tests * Reorganize HTTPX instrumentation * Add HTTPX HTTP/2 testing * Update cert.pem example command * Fix HTTPX host routing in tests * Combine all http ports for nginx * Update nginx settings --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent 4334b5e commit dacf155

File tree

8 files changed

+214
-82
lines changed

8 files changed

+214
-82
lines changed

.github/workflows/tests.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ jobs:
4343
- mongodb
4444
- mssql
4545
- mysql
46+
- nginx
4647
- postgres16
4748
- postgres9
4849
- rabbitmq
@@ -250,6 +251,69 @@ jobs:
250251
path: ./**/.coverage.*
251252
retention-days: 1
252253

254+
nginx:
255+
env:
256+
TOTAL_GROUPS: 1
257+
258+
strategy:
259+
fail-fast: false
260+
matrix:
261+
group-number: [1]
262+
263+
runs-on: ubuntu-latest
264+
container:
265+
image: ghcr.io/newrelic/newrelic-python-agent-ci:latest
266+
options: >-
267+
--add-host=host.docker.internal:host-gateway
268+
timeout-minutes: 30
269+
services:
270+
nginx:
271+
image: tpansino1643652/nginx-hello-world:latest
272+
ports:
273+
- 8080:8080
274+
- 8081:8081
275+
- 8082:8082
276+
# Set health checks to wait until nginx has started
277+
options: >-
278+
--health-cmd "service nginx status || exit 1"
279+
--health-interval 10s
280+
--health-timeout 5s
281+
--health-retries 5
282+
283+
steps:
284+
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1
285+
286+
- name: Fetch git tags
287+
run: |
288+
git config --global --add safe.directory "$GITHUB_WORKSPACE"
289+
git fetch --tags origin
290+
291+
- name: Configure pip cache
292+
run: |
293+
mkdir -p /github/home/.cache/pip
294+
chown -R $(whoami) /github/home/.cache/pip
295+
296+
- name: Get Environments
297+
id: get-envs
298+
run: |
299+
echo "envs=$(tox -l | grep '^${{ github.job }}\-' | ./.github/workflows/get-envs.py)" >> $GITHUB_OUTPUT
300+
env:
301+
GROUP_NUMBER: ${{ matrix.group-number }}
302+
303+
- name: Test
304+
run: |
305+
tox -vv -e ${{ steps.get-envs.outputs.envs }} -p auto
306+
env:
307+
TOX_PARALLEL_NO_SPINNER: 1
308+
PY_COLORS: 0
309+
310+
- name: Upload Coverage Artifacts
311+
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 4.3.1
312+
with:
313+
name: coverage-${{ github.job }}-${{ strategy.job-index }}
314+
path: ./**/.coverage.*
315+
retention-days: 1
316+
253317
postgres16:
254318
env:
255319
TOTAL_GROUPS: 2

newrelic/hooks/external_httpx.py

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -101,41 +101,28 @@ async def async_send_wrapper(wrapped, instance, args, kwargs):
101101
return await wrapped(*args, **kwargs)
102102

103103

104-
@property
105-
def nr_first_event_hooks(self):
106-
if not hasattr(self, "_nr_event_hooks"):
107-
# This branch should only be hit if agent initialize is called after
108-
# the initialization of the http client
109-
self._event_hooks = vars(self)["_event_hooks"]
110-
del vars(self)["_event_hooks"]
111-
return self._nr_event_hooks
104+
def create_nr_first_event_hooks(is_async=False):
105+
@property
106+
def nr_first_event_hooks(self):
107+
if not hasattr(self, "_nr_event_hooks"):
108+
# This branch should only be hit if agent initialize is called after
109+
# the initialization of the http client
110+
self._event_hooks = vars(self)["_event_hooks"]
111+
del vars(self)["_event_hooks"]
112+
return self._nr_event_hooks
112113

113114

114-
@nr_first_event_hooks.setter
115-
def nr_first_event_hooks(self, value):
116-
value = NewRelicFirstDict(value, is_async=False)
117-
self._nr_event_hooks = value
118-
119-
120-
@property
121-
def nr_first_event_hooks_async(self):
122-
if not hasattr(self, "_nr_event_hooks"):
123-
# This branch should only be hit if agent initialize is called after
124-
# the initialization of the http client
125-
self._event_hooks = vars(self)["_event_hooks"]
126-
del vars(self)["_event_hooks"]
127-
return self._nr_event_hooks
128-
129-
130-
@nr_first_event_hooks_async.setter
131-
def nr_first_event_hooks_async(self, value):
132-
value = NewRelicFirstDict(value, is_async=True)
133-
self._nr_event_hooks = value
115+
@nr_first_event_hooks.setter
116+
def nr_first_event_hooks(self, value):
117+
value = NewRelicFirstDict(value, is_async=is_async)
118+
self._nr_event_hooks = value
119+
120+
return nr_first_event_hooks
134121

135122

136123
def instrument_httpx_client(module):
137-
module.Client._event_hooks = nr_first_event_hooks
138-
module.AsyncClient._event_hooks = nr_first_event_hooks_async
124+
module.Client._event_hooks = create_nr_first_event_hooks(is_async=False)
125+
module.AsyncClient._event_hooks = create_nr_first_event_hooks(is_async=True)
139126

140127
wrap_function_wrapper(module, "Client.send", sync_send_wrapper)
141128
wrap_function_wrapper(module, "AsyncClient.send", async_send_wrapper)

tests/agent_unittests/cert.pem

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
This is not a secret key!
22
This private key is used only for testing and is not functionally used in the agent.
33
To generate a new key and certificate, use the following.
4-
openssl req -nodes -newkey rsa:2048 -x509 -keyout key.pem -out cert.pem -subj '/CN=localhost' -days 3650
4+
openssl req -nodes -newkey rsa:2048 -x509 -keyout cert.pem -out cert.pem -subj '/CN=localhost' -days 3650
55
-----BEGIN PRIVATE KEY-----
66
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDYF0U/0zXikonW
77
Ez532avkDL1QbQ8Yz5ULMwZz8j+cLEhdw/4pQJ7Dox6KEZbsan1nZZqpcZWT0d39

tests/external_httpx/conftest.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
collector_agent_registration_fixture,
2121
collector_available_fixture,
2222
)
23+
from testing_support.db_settings import nginx_settings
2324

2425
_default_settings = {
2526
"package_reporting.enabled": False, # Turn off package reporting for testing as it causes slow downs.
@@ -40,3 +41,24 @@ def httpx():
4041
import httpx
4142

4243
return httpx
44+
45+
46+
@pytest.fixture(scope="session")
47+
def real_server():
48+
settings = nginx_settings()[0]
49+
50+
class RealHTTP2Server:
51+
host = settings["host"]
52+
port = settings["port"]
53+
54+
yield RealHTTP2Server
55+
56+
57+
@pytest.fixture(scope="function")
58+
def sync_client(httpx):
59+
return httpx.Client()
60+
61+
62+
@pytest.fixture(scope="function")
63+
def async_client(httpx):
64+
return httpx.AsyncClient()

0 commit comments

Comments
 (0)