Skip to content

Commit

Permalink
Merge branch 'main' into ci-firefox
Browse files Browse the repository at this point in the history
Signed-off-by: Lars Eggert <[email protected]>
  • Loading branch information
larseggert authored May 6, 2024
2 parents a4263eb + adb6507 commit 9779a67
Show file tree
Hide file tree
Showing 35 changed files with 380 additions and 375 deletions.
2 changes: 1 addition & 1 deletion .github/actions/pr-comment/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ inputs:
runs:
using: composite
steps:
- uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
- uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
run-id: ${{ github.event.workflow_run.id }}
name: ${{ inputs.name }}
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ jobs:
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
# Don't increase beyond what Firefox is currently using:
# https://firefox-source-docs.mozilla.org/writing-rust-code/update-policy.html#schedule
rust-toolchain: [1.74.0, stable, nightly]
# https://searchfox.org/mozilla-central/search?q=MINIMUM_RUST_VERSION&path=python/mozboot/mozboot/util.py
# Keep in sync with Cargo.toml
rust-toolchain: [1.76.0, stable, nightly]
type: [debug]
include:
- os: ubuntu-latest
Expand Down Expand Up @@ -151,7 +152,7 @@ jobs:
if: success() || failure()

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # v4.3.0
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1
with:
file: lcov.info
fail_ci_if_error: false
Expand Down
79 changes: 62 additions & 17 deletions .github/workflows/qns.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
name: QNS

on:
schedule:
- cron: '42 3 * * 2,5' # Runs at 03:42 UTC (m and h chosen arbitrarily) twice a week.
workflow_dispatch:
push:
branches: ["main"]
paths-ignore: ["*.md", "*.png", "*.svg", "LICENSE-*"]
pull_request:
branches: ["main"]
paths-ignore: ["*.md", "*.png", "*.svg", "LICENSE-*"]
merge_group:
schedule:
# Run at 1 AM each day, so there is a `main`-branch baseline in the cache.
- cron: '0 1 * * *'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
Expand Down Expand Up @@ -60,7 +65,6 @@ jobs:
platforms: 'linux/amd64, linux/arm64'

- uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0
if: github.event_name == 'pull_request'
id: docker_build_and_push
with:
tags: ${{ steps.meta.outputs.tags }}
Expand All @@ -72,13 +76,11 @@ jobs:
outputs: type=docker,dest=/tmp/${{ env.LATEST }}.tar

- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
if: github.event_name == 'pull_request'
with:
name: '${{ env.LATEST }} Docker image'
path: /tmp/${{ env.LATEST }}.tar

implementations:
if: ${{ github.event_name == 'pull_request' }}
name: Determine interop pairs
needs: docker-image
runs-on: ubuntu-latest
Expand Down Expand Up @@ -120,7 +122,6 @@ jobs:
} >> "$GITHUB_OUTPUT"
run-qns:
if: ${{ github.event_name == 'pull_request' }}
name: Run QNS
needs: implementations
strategy:
Expand All @@ -129,7 +130,7 @@ jobs:
pair: ${{ fromJson(needs.implementations.outputs.pairs) }}
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
- uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: '${{ env.LATEST }} Docker image'
path: /tmp
Expand All @@ -152,18 +153,27 @@ jobs:
implementations: ${{ needs.implementations.outputs.implementations }}

report:
if: ${{ always() && github.event_name == 'pull_request' }}
name: Report results
needs: run-qns
runs-on: ubuntu-latest
steps:
- name: Download cached main-branch results
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
with:
path: results-main
key: qns-${{ runner.os }}-${{ github.sha }}
restore-keys: qns-${{ runner.os }}-

- uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
- uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
- uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
pattern: '*results'
path: results

- run: |
ls -l results-main || true
cat results-main/result.json || true
echo "[]" > result.json
for RUN in results/*; do
[ -e "$RUN/result.json" ] || continue
CLIENT=$(jq -r < "$RUN/result.json" '.clients[0]')
Expand Down Expand Up @@ -193,22 +203,57 @@ jobs:
echo "**$RESULT**"
} >> "$GROUP.md"
done
jq < "$RUN/grouped.json" ". += { client: \"$CLIENT\", server: \"$SERVER\" }" > new.json && \
jq < result.json --argjson new "$(cat new.json)" '. += [$new]' > result.json.tmp && \
rm new.json && \
mv result.json.tmp result.json
done
DIFFER='def post_recurse(f): def r: (f | select(. != null) | r), .; r; def post_recurse: post_recurse(.[]?); (. | (post_recurse | arrays) |= sort)'
diff <(jq -S "$DIFFER" results-main/result.json) <(jq -S "$DIFFER" result.json) || true
diff -Baur results-main/result.json result.json || true
{
echo "### Failed Interop Tests"
echo "[QUIC Interop Runner](https://github.com/quic-interop/quic-interop-runner), *client* vs. *server*"
cat failed.md
echo "<details><summary>Succeeded and unsupported tests</summary>"
SHA=$(cat results-main/baseline-sha.txt || true)
if [ -n "$SHA" ]; then
{
echo "Interop failures relative to $SHA."
echo
} >> results.md
fi
if [ -e failed.md ]; then
echo "[QUIC Interop Runner](https://github.com/quic-interop/quic-interop-runner), *client* vs. *server*"
cat failed.md
else
echo "None :tada:"
fi
echo "<details><summary>All results</summary>"
echo
for GROUP in succeeded unsupported; do
echo
echo "### ${GROUP^} Interop Tests"
echo
cat "$GROUP.md"
echo
if [ -e "$GROUP.md" ]; then
echo "[QUIC Interop Runner](https://github.com/quic-interop/quic-interop-runner), *client* vs. *server*"
cat "$GROUP.md"
else
echo "None :question:"
fi
done
echo
echo "</details>"
} >> comment.md
- name: Remember main-branch push URL
if: github.ref == 'refs/heads/main'
run: echo "${{ github.sha }}" > baseline-sha.txt

- name: Cache main-branch results
if: github.ref == 'refs/heads/main'
uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
with:
path: |
result.json
baseline-sha.txt
key: qns-${{ runner.os }}-${{ github.sha }}

- uses: ./.github/actions/pr-comment-data-export
with:
name: ${{ github.workflow }}
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ resolver = "2"
homepage = "https://github.com/mozilla/neqo/"
repository = "https://github.com/mozilla/neqo/"
authors = ["The Neqo Authors <[email protected]>"]
version = "0.7.5"
version = "0.7.6"
# Keep in sync with `.rustfmt.toml` `edition`.
edition = "2021"
license = "MIT OR Apache-2.0"
# Don't increase beyond what Firefox is currently using:
# https://searchfox.org/mozilla-central/search?q=MINIMUM_RUST_VERSION&path=python/mozboot/mozboot/util.py
rust-version = "1.74.0"
# Keep in sync with .github/workflows/check.yml
rust-version = "1.76.0"

[workspace.dependencies]
log = { version = "0.4", default-features = false }
Expand Down
35 changes: 24 additions & 11 deletions neqo-bin/src/client/http09.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ use std::{
use neqo_common::{event::Provider, qdebug, qinfo, qwarn, Datagram};
use neqo_crypto::{AuthenticationStatus, ResumptionToken};
use neqo_transport::{
Connection, ConnectionError, ConnectionEvent, EmptyConnectionIdGenerator, Error, Output, State,
CloseReason, Connection, ConnectionEvent, EmptyConnectionIdGenerator, Error, Output, State,
StreamId, StreamType,
};
use url::Url;

use super::{get_output_file, qlog_new, Args, Res};
use super::{get_output_file, qlog_new, Args, CloseState, Res};

pub struct Handler<'a> {
streams: HashMap<StreamId, Option<BufWriter<File>>>,
Expand Down Expand Up @@ -142,6 +142,26 @@ pub(crate) fn create_client(
Ok(client)
}

impl TryFrom<&State> for CloseState {
type Error = CloseReason;

fn try_from(value: &State) -> Result<Self, Self::Error> {
let (state, error) = match value {
State::Closing { error, .. } | State::Draining { error, .. } => {
(CloseState::Closing, error)
}
State::Closed(error) => (CloseState::Closed, error),
_ => return Ok(CloseState::NotClosing),
};

if error.is_error() {
Err(error.clone())
} else {
Ok(state)
}
}
}

impl super::Client for Connection {
fn process_output(&mut self, now: Instant) -> Output {
self.process_output(now)
Expand All @@ -163,15 +183,8 @@ impl super::Client for Connection {
}
}

fn is_closed(&self) -> Result<bool, ConnectionError> {
match self.state() {
State::Closed(
ConnectionError::Transport(neqo_transport::Error::NoError)
| ConnectionError::Application(0),
) => Ok(true),
State::Closed(err) => Err(err.clone()),
_ => Ok(false),
}
fn is_closed(&self) -> Result<CloseState, CloseReason> {
self.state().try_into()
}

fn stats(&self) -> neqo_transport::Stats {
Expand Down
35 changes: 23 additions & 12 deletions neqo-bin/src/client/http3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ use neqo_common::{event::Provider, hex, qdebug, qinfo, qwarn, Datagram, Header};
use neqo_crypto::{AuthenticationStatus, ResumptionToken};
use neqo_http3::{Error, Http3Client, Http3ClientEvent, Http3Parameters, Http3State, Priority};
use neqo_transport::{
AppError, Connection, ConnectionError, EmptyConnectionIdGenerator, Error as TransportError,
Output, StreamId,
AppError, CloseReason, Connection, EmptyConnectionIdGenerator, Error as TransportError, Output,
StreamId,
};
use url::Url;

use super::{get_output_file, qlog_new, Args, Res};
use super::{get_output_file, qlog_new, Args, CloseState, Res};

pub(crate) struct Handler<'a> {
#[allow(
Expand Down Expand Up @@ -105,17 +105,28 @@ pub(crate) fn create_client(
Ok(client)
}

impl super::Client for Http3Client {
fn is_closed(&self) -> Result<bool, ConnectionError> {
match self.state() {
Http3State::Closed(
ConnectionError::Transport(neqo_transport::Error::NoError)
| ConnectionError::Application(0),
) => Ok(true),
Http3State::Closed(err) => Err(err.clone()),
_ => Ok(false),
impl TryFrom<Http3State> for CloseState {
type Error = CloseReason;

fn try_from(value: Http3State) -> Result<Self, Self::Error> {
let (state, error) = match value {
Http3State::Closing(error) => (CloseState::Closing, error),
Http3State::Closed(error) => (CloseState::Closed, error),
_ => return Ok(CloseState::NotClosing),
};

if error.is_error() {
Err(error.clone())
} else {
Ok(state)
}
}
}

impl super::Client for Http3Client {
fn is_closed(&self) -> Result<CloseState, CloseReason> {
self.state().try_into()
}

fn process_output(&mut self, now: Instant) -> Output {
self.process_output(now)
Expand Down
29 changes: 17 additions & 12 deletions neqo-bin/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use neqo_crypto::{
init, Cipher, ResumptionToken,
};
use neqo_http3::Output;
use neqo_transport::{AppError, ConnectionError, ConnectionId, Version};
use neqo_transport::{AppError, CloseReason, ConnectionId, Version};
use qlog::{events::EventImportance, streamer::QlogStreamer};
use tokio::time::Sleep;
use url::{Origin, Url};
Expand Down Expand Up @@ -80,11 +80,11 @@ impl From<neqo_transport::Error> for Error {
}
}

impl From<neqo_transport::ConnectionError> for Error {
fn from(err: neqo_transport::ConnectionError) -> Self {
impl From<neqo_transport::CloseReason> for Error {
fn from(err: neqo_transport::CloseReason) -> Self {
match err {
ConnectionError::Transport(e) => Self::TransportError(e),
ConnectionError::Application(e) => Self::ApplicationError(e),
CloseReason::Transport(e) => Self::TransportError(e),
CloseReason::Application(e) => Self::ApplicationError(e),
}
}
}
Expand Down Expand Up @@ -345,6 +345,12 @@ trait Handler {
fn take_token(&mut self) -> Option<ResumptionToken>;
}

enum CloseState {
NotClosing,
Closing,
Closed,
}

/// Network client, e.g. [`neqo_transport::Connection`] or [`neqo_http3::Http3Client`].
trait Client {
fn process_output(&mut self, now: Instant) -> Output;
Expand All @@ -355,11 +361,7 @@ trait Client {
fn close<S>(&mut self, now: Instant, app_error: AppError, msg: S)
where
S: AsRef<str> + Display;
/// Returns [`Some(_)`] if the connection is closed.
///
/// Note that connection was closed without error on
/// [`Some(ConnectionError::Transport(TransportError::NoError))`].
fn is_closed(&self) -> Result<bool, ConnectionError>;
fn is_closed(&self) -> Result<CloseState, CloseReason>;
fn stats(&self) -> neqo_transport::Stats;
}

Expand All @@ -381,16 +383,19 @@ impl<'a, H: Handler> Runner<'a, H> {
continue;
}

#[allow(clippy::match_same_arms)]
match (handler_done, self.client.is_closed()?) {
// more work
(false, _) => {}
// no more work, closing connection
(true, false) => {
(true, CloseState::NotClosing) => {
self.client.close(Instant::now(), 0, "kthxbye!");
continue;
}
// no more work, already closing connection
(true, CloseState::Closing) => {}
// no more work, connection closed, terminating
(true, true) => break,
(true, CloseState::Closed) => break,
}

match ready(self.socket, self.timeout.as_mut()).await? {
Expand Down
2 changes: 1 addition & 1 deletion neqo-crypto/src/agentio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const PR_FAILURE: PrStatus = prio::PRStatus::PR_FAILURE;

/// Convert a pinned, boxed object into a void pointer.
pub fn as_c_void<T: Unpin>(pin: &mut Pin<Box<T>>) -> *mut c_void {
(Pin::into_inner(pin.as_mut()) as *mut T).cast()
(std::ptr::from_mut::<T>(Pin::into_inner(pin.as_mut()))).cast()
}

/// A slice of the output.
Expand Down
Loading

0 comments on commit 9779a67

Please sign in to comment.