-
Notifications
You must be signed in to change notification settings - Fork 722
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
test: Add more unit test coverage to s2n_send.c #3347
Conversation
tests/unit/s2n_send_test.c
Outdated
EXPECT_SUCCESS(s2n_connection_set_ctx(conn, (void*)&total_bytes_to_send)); | ||
EXPECT_SUCCESS(s2n_connection_set_send_cb(conn, s2n_counted_send_fn)); | ||
EXPECT_SUCCESS(s2n_connection_set_send_ctx(conn, (void*) conn)); |
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.
Couldn't you just put total_bytes_to_send in the send context and avoid the extra indirection?
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 need to check conn->current_user_data_consumed
to get the amount of user data sent in the callback :/. I can't rely on the len in the callback because it's encrypted.
tests/unit/s2n_send_test.c
Outdated
EXPECT_EQUAL(conn->current_user_data_consumed + written, conn->active_application_bytes_consumed); | ||
|
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.
This line might need a comment, bc I'm not sure the variable names describe what's happening well. Is conn->current_user_data_consumed the remaining data to write?
If the variable name isn't great but would be a pain to change, you could write an EXPECT macro that describes what you're looking for. Like maybe "EXPECT_WRITTEN(written)"?
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 rewrite this to make it clearer.
conn->active_application_bytes_consumed
is the total amount of data that has been processed in s2n_send. It resets to 0 w/e the dynamic record thresholds are hit if they are enabled. In this case it is not enabled so we can use it to track the amount of bytes that have been sent to the socket (successful + unsuccessful).
conn->current_user_data_consumed
is tracking the amount of data that has been successfully flushed.
In the case of a partial write conn->current_user_data_consumed is set to the amount of bytes that were not written, and then we return the total amount of bytes that we were able to send.
So this check is to make sure that written + current_user_data_consumed would be equal to the total amount of bytes we have put in the conn->out stuffer, but current_user_data_consumed tracking what we still need to send.
tests/unit/s2n_send_test.c
Outdated
/* Subsequent writes should only be decreasing. */ | ||
s2n_custom_send_fn_called = false; | ||
EXPECT_FAILURE_WITH_ERRNO(s2n_send(conn, large_data.data, written - large_data.size, &blocked), S2N_ERR_SEND_SIZE); |
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 not sure what this is testing. Isn't written - large_data.size
negative? Or are you relying on it overflowing an unsigned parameter? But then the test name talks about a "smaller buffer".
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 checking this conditional
Line 136 in ac56bca
S2N_ERROR_IF(conn->current_user_data_consumed > total_size, S2N_ERR_SEND_SIZE); |
Basically if s2n_send has already sent more than the total size of the send it implies an error in the user logic because the message should've been flushed and conn->current_user_data_consumed
should be moved back to 0!
I'll add a comment to clear this up.
I wrote this test this way because I think it will be the most common way a user may trip up on this
tests/unit/s2n_send_test.c
Outdated
|
||
/* Until we hit the dynamic record resize threshold we expect that the records are divisible | ||
* by the s2n_record_min_write_payload_size. */ |
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.
Can you expand on this? Why is this the expected behavior, and why is it important that this is true?
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.
Will do 👍
tests/unit/s2n_send_test.c
Outdated
uint16_t min_payload_size = 0; | ||
POSIX_GUARD_RESULT(s2n_record_min_write_payload_size(conn, &min_payload_size)); | ||
EXPECT_EQUAL(1398, min_payload_size); |
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.
Where does "1398" come from?
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 add a comment to say as much but this is here because this number is the max amount of bytes that can be stuffed into a single ethernet frame.
So when dynamic mode is used it will use this as the max write size until the bytes written threshold is reached.
I have this check here so if for some reason this value changes the test case can be revisited (Will add a comment for this as well)
tests/unit/s2n_send_test.c
Outdated
|
||
/* s2n_send partial writes are flushed in proceeding sends */ |
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.
Nit, I don't think "proceeding" is what you mean here. How about, "the next send", "later sends" or "subsequent sends".
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.
Okay will update this to "subsequent sends"
tests/unit/s2n_send_test.c
Outdated
|
||
/* Assume we have a partial write of sizeof(test_data) - 1 that was successful. | ||
* The subsequent socket write failed with EAGAIN, and control has returned to the application.*/ |
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.
Why can we assume this? Doesn't s2n_partial_socket_send_fn write len-3?
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.
Ah oops, will update this comment. At one time it was at len-1, and I forgot to update this comment when I changed it
tests/unit/s2n_send_test.c
Outdated
EXPECT_SUCCESS(s2n_connection_set_send_cb(conn, s2n_send_always_passes_fn)); | ||
EXPECT_SUCCESS(s2n_send(conn, test_data, sizeof(test_data), &blocked)); | ||
EXPECT_TRUE(s2n_custom_send_fn_called); | ||
EXPECT_EQUAL(conn->current_user_data_consumed, 0); | ||
EXPECT_EQUAL(blocked, S2N_NOT_BLOCKED); |
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.
How does this prove that we flushed the previous partial write?
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 assumed EXPECT_EQUAL(conn->current_user_data_consumed, 0);
would be enough, but you are right! I will add another check that there is no data available in the out stuffer.
32af85a
to
e6c0825
Compare
tests/unit/s2n_send_test.c
Outdated
EXPECT_SUCCESS(s2n_stuffer_wipe(&conn->out)); | ||
EXPECT_SUCCESS(s2n_stuffer_write_bytes(&conn->out, buf, len)); | ||
|
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.
Why is your send callback touching internal connection buffers? A customer's send function couldn't do that, since s2n_connection is opaque.
Wouldn't this modify the behavior of s2n_send in unexpected ways that invalidate the test? Are you sure that you aren't papering over a bug?
Same for s2n_send_mitigates_beast_fn, s2n_dynamic_record_sizing_fn, and s2n_byte_limit_send_fn
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.
Oh I've forgotten why I introduced these. Removing them.
tests/unit/s2n_send_test.c
Outdated
/* Allocate 32KB so it takes multiple records to send complete data. */ | ||
EXPECT_SUCCESS(s2n_alloc(&large_data, 1 << 15)); |
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.
Don't we have a constant somewhere representing the maximum record size? Could we use that here rather than "<<15"?
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.
This integer is larger than the maximum record size so the message is chunked across multiple records.
I'll move this into a macro
tests/unit/s2n_send_test.c
Outdated
|
||
/* s2n_flush will send attempt to send the out stuffer before closing a connection. */ |
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.
Do you mean "will send" or "will attempt to send"? This is kind of important-- there's a big different between making one best-effort attempt then closing vs blocking until the send completes, and this test doesn't distinguish since your send always succeeds.
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.
Updated to "will send"
tests/unit/s2n_send_test.c
Outdated
/* s2n_send enforces RE-ENTRENCY. */ | ||
{ |
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.
This is actually one of the few s2n_send tests we already have ;) https://github.com/aws/s2n-tls/blob/main/tests/unit/s2n_send_test.c#L71-L92
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.
Ah oops, removed!
Co-authored-by: Lindsay Stewart <[email protected]>
Co-authored-by: Lindsay Stewart <[email protected]>
a8e1e0f
to
fca30c2
Compare
Resolved issues:
None
Description of changes:
This PR adds more unit test coverage to s2n_send.c.
Call-outs:
Address any potentially confusing code. Is there code added that needs to be cleaned up later? Is there code that is missing because it’s still in development?
Testing:
How is this change tested (unit tests, fuzz tests, etc.)? Are there any testing steps to be verified by the reviewer?
N/A
Is this a refactor change? If so, how have you proved that the intended behavior hasn't changed?
N/A
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.