Skip to content

Conversation

BrendanChou
Copy link
Collaborator

@BrendanChou BrendanChou commented Jun 2, 2025

Fix #1041

Also small non-runtime changes due to this fix:

  • Includes a test in codec.rs to demonstrate a test that would have previously failed (previously would panic with runtime stalled)
  • Modifies a test in handshake.rs that was previously dropping stream/sink variables. This wasn't causing an issue before, but now simulates a network disconnection so we don't want to drop these variables

@BrendanChou BrendanChou marked this pull request as ready for review June 2, 2025 15:42
@danlaine
Copy link
Collaborator

danlaine commented Jun 2, 2025

Another approach we could take is to rely on the Arc's reference count. If both the sink and stream are alive, the Arc's strong_count will be 2. If one is dropped, the reference count goes to 1, meaning Arc::strong_count(&channel) == 1 implies "the other side of this connection is dead". This would allow us to remove the sink_alive and stream_alive fields. On the other hand, if we took this approach, it would break if we ever modify the code to allow the Channel to be cloned (because it would increase the Arc's ref count.) It seems unlikely that we would add the ability to Clone a channel, though.

What do you think of this approach @BrendanChou ?

@danlaine
Copy link
Collaborator

danlaine commented Jun 2, 2025

Another thing to note: if we took the approach of relying on the Arc's ref count, we would still need to do synchronization on drop to prevent races.

@BrendanChou
Copy link
Collaborator Author

That's a reasonable point. I think the explicit boolean way is slightly better due to being more explicit. An extra two fields can be a bit annoying but the complexity is not bad since it's all contained within this single file.

Overall I would leave it as-is

Comment on lines 200 to 241
#[test]
fn test_recv_error() {
let (sink, mut stream) = Channel::init();
let executor = deterministic::Runner::default();

// If the oneshot sender is dropped before the oneshot receiver is resolved,
// the recv function should return an error.
executor.start(|_| async move {
let (v, _) = join!(stream.recv(vec![0; 5]), async {
// Take the waiter and drop it.
sink.channel.lock().unwrap().waiter.take();
},);
assert!(matches!(v, Err(Error::RecvFailed)));
});
}

#[test]
fn test_send_error() {
let (mut sink, mut stream) = Channel::init();
let executor = deterministic::Runner::default();

// If the waiter value has a min, but the oneshot receiver is dropped,
// the send function should return an error when attempting to send the data.
executor.start(|context| async move {
// Create a waiter using a recv call.
// But then drop the receiver.
select! {
v = stream.recv( vec![0;5]) => {
panic!("unexpected value: {:?}", v);
},
_ = context.sleep(Duration::from_millis(100)) => {
"timeout"
},
};
drop(stream);

// Try to send a message (longer than the requested amount), but the receiver is dropped.
let result = sink.send(b"hello world".to_vec()).await;
assert!(matches!(result, Err(Error::Closed)));
});
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the new tests make these redundant

@BrendanChou BrendanChou merged commit da5cf18 into main Jun 2, 2025
17 checks passed
@BrendanChou BrendanChou deleted the bc/1039-frame branch June 2, 2025 22:31
Copy link

codecov bot commented Jun 2, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 91.05%. Comparing base (6452e32) to head (3937b3d).
Report is 3 commits behind head on main.

@@            Coverage Diff             @@
##             main    #1042      +/-   ##
==========================================
+ Coverage   90.99%   91.05%   +0.05%     
==========================================
  Files         191      191              
  Lines       54232    54427     +195     
==========================================
+ Hits        49347    49557     +210     
+ Misses       4885     4870      -15     
Files with missing lines Coverage Δ
runtime/src/mocks.rs 99.49% <100.00%> (+0.86%) ⬆️
stream/src/public_key/handshake.rs 100.00% <100.00%> (ø)
stream/src/utils/codec.rs 100.00% <100.00%> (ø)

... and 4 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6452e32...3937b3d. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[runtime] Mock network channel doesn't simulate disconnection

2 participants