-
Notifications
You must be signed in to change notification settings - Fork 3
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
Use proxy tester for better verification, and fix timeout support #129
Conversation
49cd556
to
aa3423c
Compare
718481c
to
3d8eba5
Compare
dd6d1bc
to
864811f
Compare
Here is an example test_heartbeat output. The
|
1bea81a
to
0a709e7
Compare
a3554dc
to
3b1804b
Compare
@@ -20,7 +20,7 @@ repos: | |||
rev: v3.19.1 | |||
hooks: | |||
- id: pyupgrade | |||
args: [--py36-plus] | |||
args: [--py36-plus, --keep-percent-format] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what can I say I like percents
|
||
|
||
def attempt_heartbeat(channel=None, path=None, wait=False): | ||
global DRY_RUN | ||
line = "------------------------" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved the print statements, which are only needed when calling from the command line, to the main()
function where they belong
_print("anaconda-anon-usage heartbeat", standalone=True) | ||
_print(line, standalone=True) | ||
|
||
def attempt_heartbeat(prefix=None, dry_run=False, channel=None, path=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added the prefix
argument so that this one function controls the user agent
_print("anaconda-anon-usage heartbeat") | ||
_print(line) | ||
|
||
def environment_path(s): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL that the type
argument in argparse arguments is a callable:
https://stackoverflow.com/a/37472037
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL!
@@ -19,8 +20,6 @@ | |||
if os.path.isfile("/etc/conda/machine_token"): | |||
expected += ("m",) | |||
|
|||
os.environ["ANACONDA_ANON_USAGE_DEBUG"] = "1" | |||
os.environ["ANACONDA_HEARTBEAT_DRY_RUN"] = "1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for these anymore, because we are mining the heartbeat information directly from the requests actually made.
@@ -1,2 +1,3 @@ | |||
pytest | |||
pytest-cov | |||
cryptography |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The proxy tester does require the cryptography module in order to do certificate generation
need_header = True | ||
for hval in ("true", "false"): | ||
os.environ["CONDA_ANACONDA_HEARTBEAT"] = hval | ||
for hval in ("true", "false", "delay"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"delay" mode is enabled, but the network connection is blocked, so we're testing that no heartbeat was actually sent.
_print("anaconda-anon-usage heartbeat") | ||
_print(line) | ||
|
||
def environment_path(s): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL!
@@ -0,0 +1,535 @@ | |||
#!/usr/bin/env python3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll need some time to check the AI's job to implement this correctly, my trust in AI slop is limited :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually generating a bunch of tests for the script using Claude. I found an interesting case with this approach! I will keep you posted.
[EDIT: More improvements listed below]
For another project I worked with Claude.ai to develop a single-file proxy tester script. This script launches a man-in-the-middle proxy to capture and log requests that the child script is generating, making it easier to do live testing. One particular feature of the tester is that it can be run in a mode that intercepts all requests and returns a fixed status code, so you can actually do live testing without disturbing the upstream server.
I thought I'd bring it over here and use it for test_config and test_heartbeat. This is better for test_heartbeat in particular because I was running it in "dry run" mode during the tests here—no actual requests are being generated. This is confirming that in fact, yes, the script is indeed making the intended request and using the intended user agent.
And wouldn't you know it? Doing this uncovered an issue with how timeouts are being handled. In short, the thread that is making the request was being shut down as soon as the rest of the activation work was complete, and that is quite often not long enough for the connection to be made. Forcing the process to block until the connection attempt is complete is therefore necessary, but then you have to make sure that the connect timeout is reasonably short so that the user does not suffer unreasonable activation delays if the internet connection is down or is slow.
I added a delay capability into the proxy tester to emulate a stalled connection, and then I added a mode to
test_heartbeats.py
that uses that capability to make sure that the heartbeat is not sent if the delay is too long.MORE IMPROVEMENTS:
test_heartbeat
module quite a bit. Now we are recovering the full heartbeat URL as well as the user agent from the actual request logs, not the dry run debug output.attempt_heartbeat
for simpler calling in the patched activate function.-n/--name
and-p/--prefix
command-line arguments to thepython -m anaconda_anon_usage.heartbeat
command so we can exercise the above argument